Merge branch 'master' of ssh://git.citadel.org/appl/gitroot/citadel
authorWilfried Goesgens <dothebart@citadel.org>
Thu, 12 Sep 2013 20:59:03 +0000 (22:59 +0200)
committerWilfried Goesgens <dothebart@citadel.org>
Thu, 12 Sep 2013 20:59:03 +0000 (22:59 +0200)
Conflicts:
citadel/modules/network/serv_network.c
citadel/modules/smtp/serv_smtp.c
citadel/modules/smtp/smtp_util.c

60 files changed:
citadel/Makefile.in
citadel/citserver.c
citadel/citserver.h
citadel/config.c
citadel/config.h
citadel/ctdl_message.c [new file with mode: 0644]
citadel/database.c
citadel/euidindex.c
citadel/housekeeping.c
citadel/include/ctdl_module.h
citadel/internet_addressing.c
citadel/internet_addressing.h
citadel/journaling.c
citadel/modules/autocompletion/serv_autocompletion.c
citadel/modules/blog/serv_blog.c
citadel/modules/calendar/serv_calendar.c
citadel/modules/clamav/serv_virus.c
citadel/modules/dspam/serv_dspam.c
citadel/modules/expire/serv_expire.c
citadel/modules/extnotify/extnotify_main.c
citadel/modules/extnotify/funambol65.c
citadel/modules/fulltext/serv_fulltext.c
citadel/modules/imap/imap_fetch.c
citadel/modules/imap/imap_misc.c
citadel/modules/imap/imap_search.c
citadel/modules/imap/imap_store.c
citadel/modules/inetcfg/serv_inetcfg.c
citadel/modules/instmsg/serv_instmsg.c
citadel/modules/migrate/serv_migrate.c
citadel/modules/network/netspool.h
citadel/modules/network/serv_netfilter.c
citadel/modules/network/serv_netmail.c
citadel/modules/network/serv_netspool.c
citadel/modules/network/serv_network.c
citadel/modules/notes/serv_notes.c
citadel/modules/pop3client/serv_pop3client.c
citadel/modules/rssclient/rss_atom_parser.c
citadel/modules/rssclient/rss_atom_parser.h
citadel/modules/rssclient/serv_rssclient.c
citadel/modules/sieve/serv_sieve.c
citadel/modules/smtp/serv_smtp.c
citadel/modules/smtp/serv_smtpeventclient.c
citadel/modules/smtp/serv_smtpqueue.c
citadel/modules/smtp/smtp_util.c
citadel/modules/spam/serv_spam.c
citadel/modules/vcard/serv_vcard.c
citadel/modules/wiki/serv_wiki.c
citadel/modules/xmpp/xmpp_presence.c
citadel/msgbase.c
citadel/msgbase.h
citadel/netconfig.c
citadel/room_ops.c
citadel/room_ops.h
citadel/scripts/mk_module_init.sh
citadel/server.h
citadel/techdoc/hack.txt
citadel/user_ops.c
citadel/user_ops.h
libcitadel/lib/libcitadel.h
libcitadel/lib/tools.c

index 8a982d920490c3ae1e1acced8b525a137e2d986e..8f8e4724a00e743225c425e6fdad95d78b99cd49 100644 (file)
@@ -78,7 +78,7 @@ SOURCES=utils/aidepost.c utils/citmail.c \
        citserver.c clientsocket.c config.c control.c $(DATABASE) \
        domain.c serv_extensions.c file_ops.c genstamp.c \
        housekeeping.c ical_dezonify.c internet_addressing.c ecrash.c \
-       locate_host.c auth.c msgbase.c parsedate.c \
+       locate_host.c auth.c msgbase.c ctdl_message.c parsedate.c \
        room_ops.c euidindex.c server_main.c ldap.c \
        support.c sysdep.c user_ops.c journaling.c threads.c \
        context.c event_client.c netconfig.c nttlist.c md5.c
@@ -131,7 +131,7 @@ SERV_OBJS = server_main.o utillib/citadel_dirs.o event_client.o \
        user_ops.o citserver.o sysdep.o serv_extensions.o \
        $(DATABASE:.c=.o) domain.o \
        control.o config.o support.o room_ops.o \
-       file_ops.o msgbase.o euidindex.o \
+       file_ops.o msgbase.o ctdl_message.o euidindex.o \
        locate_host.o housekeeping.o ical_dezonify.o \
        internet_addressing.o journaling.o \
        parsedate.o genstamp.o ecrash.o threads.o context.o \
index d91b976b059bc003bc3a4bd2cc06dde4fc0602b0..a06940d68c6b55c1415c8d8e565f71763a7f79bf 100644 (file)
@@ -492,6 +492,40 @@ void cmd_iden(char *argbuf)
        cprintf("%d Ok\n",CIT_OK);
 }
 
+
+/* 
+ * help_subst()  -  support routine for help file viewer
+ */
+void help_subst(char *strbuf, char *source, char *dest)
+{
+       char workbuf[SIZ];
+       int p;
+
+       while (p = pattern2(strbuf, source), (p >= 0)) {
+               strcpy(workbuf, &strbuf[p + strlen(source)]);
+               strcpy(&strbuf[p], dest);
+               strcat(strbuf, workbuf);
+       }
+}
+
+void do_help_subst(char *buffer)
+{
+       char buf2[16];
+
+       help_subst(buffer, "^nodename", config.c_nodename);
+       help_subst(buffer, "^humannode", config.c_humannode);
+       help_subst(buffer, "^fqdn", config.c_fqdn);
+       help_subst(buffer, "^username", CC->user.fullname);
+       snprintf(buf2, sizeof buf2, "%ld", CC->user.usernum);
+       help_subst(buffer, "^usernum", buf2);
+       help_subst(buffer, "^sysadm", config.c_sysadm);
+       help_subst(buffer, "^variantname", CITADEL);
+       snprintf(buf2, sizeof buf2, "%d", config.c_maxsessions);
+       help_subst(buffer, "^maxsessions", buf2);
+       help_subst(buffer, "^bbsdir", ctdl_message_dir);
+}
+
+
 typedef const char *ccharp;
 /*
  * display system messages or help
index 94c7e8d90ab276fc527a37bbb25705bc23d6c89d..37028a7496e6b6dbd2cab569c78c9aceb4fc47d0 100644 (file)
@@ -48,6 +48,9 @@ void citproto_begin_admin_session(void);
 void GenerateRoomDisplay(char *real_room,
                         CitContext *viewed,
                         CitContext *viewer);
+
+void help_subst (char *strbuf, char *source, char *dest);
+
 extern int panic_fd;
 char CtdlCheckExpress(void);
 extern time_t server_startup_time;
index 4dc7698b45ec6420f1e385c54c48b4882a8adcd0..8f3ec9db63d7c3a964ae8b4c1b4b1b85e977f735 100644 (file)
@@ -196,6 +196,7 @@ void get_config(void) {
        }
 }
 
+long config_msgnum = 0;
 
 /*
  * Occasionally, we will need to write the config file, because some operations
@@ -217,3 +218,62 @@ void put_config(void)
        }
        syslog(LOG_EMERG, "%s: %s", file_citadel_config, strerror(errno));
 }
+
+
+
+void CtdlGetSysConfigBackend(long msgnum, void *userdata) {
+       config_msgnum = msgnum;
+}
+
+
+char *CtdlGetSysConfig(char *sysconfname) {
+       char hold_rm[ROOMNAMELEN];
+       long msgnum;
+       char *conf;
+       struct CtdlMessage *msg;
+       char buf[SIZ];
+       
+       strcpy(hold_rm, CC->room.QRname);
+       if (CtdlGetRoom(&CC->room, SYSCONFIGROOM) != 0) {
+               CtdlGetRoom(&CC->room, hold_rm);
+               return NULL;
+       }
+
+
+       /* We want the last (and probably only) config in this room */
+       begin_critical_section(S_CONFIG);
+       config_msgnum = (-1L);
+       CtdlForEachMessage(MSGS_LAST, 1, NULL, sysconfname, NULL,
+                          CtdlGetSysConfigBackend, NULL);
+       msgnum = config_msgnum;
+       end_critical_section(S_CONFIG);
+
+       if (msgnum < 0L) {
+               conf = NULL;
+       }
+       else {
+               msg = CtdlFetchMessage(msgnum, 1);
+               if (msg != NULL) {
+                       conf = strdup(msg->cm_fields[eMesageText]);
+                       CM_Free(msg);
+               }
+               else {
+                       conf = NULL;
+               }
+       }
+
+       CtdlGetRoom(&CC->room, hold_rm);
+
+       if (conf != NULL) do {
+                       extract_token(buf, conf, 0, '\n', sizeof buf);
+                       strcpy(conf, &conf[strlen(buf)+1]);
+               } while ( (!IsEmptyStr(conf)) && (!IsEmptyStr(buf)) );
+
+       return(conf);
+}
+
+
+void CtdlPutSysConfig(char *sysconfname, char *sysconfdata) {
+       CtdlWriteObject(SYSCONFIGROOM, sysconfname, sysconfdata, (strlen(sysconfdata)+1), NULL, 0, 1, 0);
+}
+
index cc4a92ac4e6234a1c45bdafe523a23a03dad0df5..f541ebfa2528cf39522b5ff6414f449981cd9c7f 100644 (file)
@@ -17,3 +17,6 @@
 void get_config(void);
 void put_config(void);
 
+char *CtdlGetSysConfig(char *sysconfname);
+void CtdlPutSysConfig(char *sysconfname, char *sysconfdata);
+
diff --git a/citadel/ctdl_message.c b/citadel/ctdl_message.c
new file mode 100644 (file)
index 0000000..4d9230b
--- /dev/null
@@ -0,0 +1,865 @@
+/*
+ * represent messages to the citadel clients
+ *
+ * Copyright (c) 1987-2012 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.
+ *
+ * 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.
+ */
+
+#include "sysdep.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+
+#include <ctype.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include "md5.h"
+
+#include <libcitadel.h>
+#include "citadel.h"
+#include "server.h"
+#include "serv_extensions.h"
+#include "database.h"
+///#include "msgbase.h"
+#include "support.h"
+#include "sysdep_decls.h"
+#include "citserver.h"
+#include "room_ops.h"
+#include "user_ops.h"
+#include "file_ops.h"
+#include "config.h"
+#include "control.h"
+#include "genstamp.h"
+#include "internet_addressing.h"
+#include "euidindex.h"
+#include "journaling.h"
+#include "citadel_dirs.h"
+#include "clientsocket.h"
+#include "threads.h"
+
+#include "ctdl_module.h"
+
+extern char *msgkeys[];
+
+
+
+/*
+ * Back end for the MSGS command: output message number only.
+ */
+void simple_listing(long msgnum, void *userdata)
+{
+       cprintf("%ld\n", msgnum);
+}
+
+
+
+/*
+ * Back end for the MSGS command: output header summary.
+ */
+void headers_listing(long msgnum, void *userdata)
+{
+       struct CtdlMessage *msg;
+
+       msg = CtdlFetchMessage(msgnum, 0);
+       if (msg == NULL) {
+               cprintf("%ld|0|||||\n", msgnum);
+               return;
+       }
+
+       cprintf("%ld|%s|%s|%s|%s|%s|\n",
+               msgnum,
+               (!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] : "")
+       );
+       CM_Free(msg);
+}
+
+/*
+ * Back end for the MSGS command: output EUID header.
+ */
+void headers_euid(long msgnum, void *userdata)
+{
+       struct CtdlMessage *msg;
+
+       msg = CtdlFetchMessage(msgnum, 0);
+       if (msg == NULL) {
+               cprintf("%ld||\n", msgnum);
+               return;
+       }
+
+       cprintf("%ld|%s|%s\n", 
+               msgnum, 
+               (!CM_IsEmpty(msg, eExclusiveID) ? msg->cm_fields[eExclusiveID] : ""),
+               (!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"));
+       CM_Free(msg);
+}
+
+
+
+/*
+ * cmd_msgs()  -  get list of message #'s in this room
+ *             implements the MSGS server command using CtdlForEachMessage()
+ */
+void cmd_msgs(char *cmdbuf)
+{
+       int mode = 0;
+       char which[16];
+       char buf[256];
+       char tfield[256];
+       char tvalue[256];
+       int cm_ref = 0;
+       int i;
+       int with_template = 0;
+       struct CtdlMessage *template = NULL;
+       char search_string[1024];
+       ForEachMsgCallback CallBack;
+
+       if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
+
+       extract_token(which, cmdbuf, 0, '|', sizeof which);
+       cm_ref = extract_int(cmdbuf, 1);
+       extract_token(search_string, cmdbuf, 1, '|', sizeof search_string);
+       with_template = extract_int(cmdbuf, 2);
+       switch (extract_int(cmdbuf, 3))
+       {
+       default:
+       case MSG_HDRS_BRIEF:
+               CallBack = simple_listing;
+               break;
+       case MSG_HDRS_ALL:
+               CallBack = headers_listing;
+               break;
+       case MSG_HDRS_EUID:
+               CallBack = headers_euid;
+               break;
+       }
+
+       strcat(which, "   ");
+       if (!strncasecmp(which, "OLD", 3))
+               mode = MSGS_OLD;
+       else if (!strncasecmp(which, "NEW", 3))
+               mode = MSGS_NEW;
+       else if (!strncasecmp(which, "FIRST", 5))
+               mode = MSGS_FIRST;
+       else if (!strncasecmp(which, "LAST", 4))
+               mode = MSGS_LAST;
+       else if (!strncasecmp(which, "GT", 2))
+               mode = MSGS_GT;
+       else if (!strncasecmp(which, "LT", 2))
+               mode = MSGS_LT;
+       else if (!strncasecmp(which, "SEARCH", 6))
+               mode = MSGS_SEARCH;
+       else
+               mode = MSGS_ALL;
+
+       if ( (mode == MSGS_SEARCH) && (!config.c_enable_fulltext) ) {
+               cprintf("%d Full text index is not enabled on this server.\n",
+                       ERROR + CMD_NOT_SUPPORTED);
+               return;
+       }
+
+       if (with_template) {
+               unbuffer_output();
+               cprintf("%d Send template then receive message list\n",
+                       START_CHAT_MODE);
+               template = (struct CtdlMessage *)
+                       malloc(sizeof(struct CtdlMessage));
+               memset(template, 0, sizeof(struct CtdlMessage));
+               template->cm_magic = CTDLMESSAGE_MAGIC;
+               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);
+                       tValueLen = extract_token(tvalue, buf, 1, '|', sizeof tvalue);
+                       for (i='A'; i<='Z'; ++i) if (msgkeys[i]!=NULL) {
+                               if (!strcasecmp(tfield, msgkeys[i])) {
+                                       CM_SetField(template, i, tvalue, tValueLen);
+                               }
+                       }
+               }
+               buffer_output();
+       }
+       else {
+               cprintf("%d  \n", LISTING_FOLLOWS);
+       }
+
+       CtdlForEachMessage(mode,
+                          ( (mode == MSGS_SEARCH) ? 0 : cm_ref ),
+                          ( (mode == MSGS_SEARCH) ? search_string : NULL ),
+                          NULL,
+                          template,
+                          CallBack,
+                          NULL);
+       if (template != NULL) CM_Free(template);
+       cprintf("000\n");
+}
+
+/*
+ * display a message (mode 0 - Citadel proprietary)
+ */
+void cmd_msg0(char *cmdbuf)
+{
+       long msgid;
+       int headers_only = HEADERS_ALL;
+
+       msgid = extract_long(cmdbuf, 0);
+       headers_only = extract_int(cmdbuf, 1);
+
+       CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0, NULL, 0, NULL, NULL);
+       return;
+}
+
+
+/*
+ * display a message (mode 2 - RFC822)
+ */
+void cmd_msg2(char *cmdbuf)
+{
+       long msgid;
+       int headers_only = HEADERS_ALL;
+
+       msgid = extract_long(cmdbuf, 0);
+       headers_only = extract_int(cmdbuf, 1);
+
+       CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1, NULL, 0, NULL, NULL);
+}
+
+
+
+/* 
+ * display a message (mode 3 - IGnet raw format - internal programs only)
+ */
+void cmd_msg3(char *cmdbuf)
+{
+       long msgnum;
+       struct CtdlMessage *msg = NULL;
+       struct ser_ret smr;
+
+       if (CC->internal_pgm == 0) {
+               cprintf("%d This command is for internal programs only.\n",
+                       ERROR + HIGHER_ACCESS_REQUIRED);
+               return;
+       }
+
+       msgnum = extract_long(cmdbuf, 0);
+       msg = CtdlFetchMessage(msgnum, 1);
+       if (msg == NULL) {
+               cprintf("%d Message %ld not found.\n", 
+                       ERROR + MESSAGE_NOT_FOUND, msgnum);
+               return;
+       }
+
+       CtdlSerializeMessage(&smr, msg);
+       CM_Free(msg);
+
+       if (smr.len == 0) {
+               cprintf("%d Unable to serialize message\n",
+                       ERROR + INTERNAL_ERROR);
+               return;
+       }
+
+       cprintf("%d %ld\n", BINARY_FOLLOWS, (long)smr.len);
+       client_write((char *)smr.ser, (int)smr.len);
+       free(smr.ser);
+}
+
+
+
+/* 
+ * Display a message using MIME content types
+ */
+void cmd_msg4(char *cmdbuf)
+{
+       long msgid;
+       char section[64];
+
+       msgid = extract_long(cmdbuf, 0);
+       extract_token(section, cmdbuf, 1, '|', sizeof section);
+       CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0, (section[0] ? section : NULL) , 0, NULL, NULL);
+}
+
+
+
+/* 
+ * Client tells us its preferred message format(s)
+ */
+void cmd_msgp(char *cmdbuf)
+{
+       if (!strcasecmp(cmdbuf, "dont_decode")) {
+               CC->msg4_dont_decode = 1;
+               cprintf("%d MSG4 will not pre-decode messages.\n", CIT_OK);
+       }
+       else {
+               safestrncpy(CC->preferred_formats, cmdbuf, sizeof(CC->preferred_formats));
+               cprintf("%d Preferred MIME formats have been set.\n", CIT_OK);
+       }
+}
+
+
+/*
+ * Open a component of a MIME message as a download file 
+ */
+void cmd_opna(char *cmdbuf)
+{
+       long msgid;
+       char desired_section[128];
+
+       msgid = extract_long(cmdbuf, 0);
+       extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section);
+       safestrncpy(CC->download_desired_section, desired_section,
+               sizeof CC->download_desired_section);
+       CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL, 0, NULL, NULL);
+}                      
+
+
+/*
+ * Open a component of a MIME message and transmit it all at once
+ */
+void cmd_dlat(char *cmdbuf)
+{
+       long msgid;
+       char desired_section[128];
+
+       msgid = extract_long(cmdbuf, 0);
+       extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section);
+       safestrncpy(CC->download_desired_section, desired_section,
+               sizeof CC->download_desired_section);
+       CtdlOutputMsg(msgid, MT_SPEW_SECTION, 0, 1, 1, NULL, 0, NULL, NULL);
+}
+
+/*
+ * message entry  -  mode 0 (normal)
+ */
+void cmd_ent0(char *entargs)
+{
+       struct CitContext *CCC = CC;
+       int post = 0;
+       char recp[SIZ];
+       char cc[SIZ];
+       char bcc[SIZ];
+       char supplied_euid[128];
+       int anon_flag = 0;
+       int format_type = 0;
+       char newusername[256];
+       char newuseremail[256];
+       struct CtdlMessage *msg;
+       int anonymous = 0;
+       char errmsg[SIZ];
+       int err = 0;
+       struct recptypes *valid = NULL;
+       struct recptypes *valid_to = NULL;
+       struct recptypes *valid_cc = NULL;
+       struct recptypes *valid_bcc = NULL;
+       char subject[SIZ];
+       int subject_required = 0;
+       int do_confirm = 0;
+       long msgnum;
+       int i, j;
+       char buf[256];
+       int newuseremail_ok = 0;
+       char references[SIZ];
+       char *ptr;
+
+       unbuffer_output();
+
+       post = extract_int(entargs, 0);
+       extract_token(recp, entargs, 1, '|', sizeof recp);
+       anon_flag = extract_int(entargs, 2);
+       format_type = extract_int(entargs, 3);
+       extract_token(subject, entargs, 4, '|', sizeof subject);
+       extract_token(newusername, entargs, 5, '|', sizeof newusername);
+       do_confirm = extract_int(entargs, 6);
+       extract_token(cc, entargs, 7, '|', sizeof cc);
+       extract_token(bcc, entargs, 8, '|', sizeof bcc);
+       switch(CC->room.QRdefaultview) {
+       case VIEW_NOTES:
+       case VIEW_WIKI:
+               extract_token(supplied_euid, entargs, 9, '|', sizeof supplied_euid);
+               break;
+       default:
+               supplied_euid[0] = 0;
+               break;
+       }
+       extract_token(newuseremail, entargs, 10, '|', sizeof newuseremail);
+       extract_token(references, entargs, 11, '|', sizeof references);
+       for (ptr=references; *ptr != 0; ++ptr) {
+               if (*ptr == '!') *ptr = '|';
+       }
+
+       /* first check to make sure the request is valid. */
+
+       err = CtdlDoIHavePermissionToPostInThisRoom(
+               errmsg,
+               sizeof errmsg,
+               NULL,
+               POST_LOGGED_IN,
+               (!IsEmptyStr(references))               /* is this a reply?  or a top-level post? */
+               );
+       if (err)
+       {
+               cprintf("%d %s\n", err, errmsg);
+               return;
+       }
+
+       /* Check some other permission type things. */
+
+       if (IsEmptyStr(newusername)) {
+               strcpy(newusername, CCC->user.fullname);
+       }
+       if (  (CCC->user.axlevel < AxAideU)
+             && (strcasecmp(newusername, CCC->user.fullname))
+             && (strcasecmp(newusername, CCC->cs_inet_fn))
+               ) {     
+               cprintf("%d You don't have permission to author messages as '%s'.\n",
+                       ERROR + HIGHER_ACCESS_REQUIRED,
+                       newusername
+                       );
+               return;
+       }
+
+
+       if (IsEmptyStr(newuseremail)) {
+               newuseremail_ok = 1;
+       }
+
+       if (!IsEmptyStr(newuseremail)) {
+               if (!strcasecmp(newuseremail, CCC->cs_inet_email)) {
+                       newuseremail_ok = 1;
+               }
+               else if (!IsEmptyStr(CCC->cs_inet_other_emails)) {
+                       j = num_tokens(CCC->cs_inet_other_emails, '|');
+                       for (i=0; i<j; ++i) {
+                               extract_token(buf, CCC->cs_inet_other_emails, i, '|', sizeof buf);
+                               if (!strcasecmp(newuseremail, buf)) {
+                                       newuseremail_ok = 1;
+                               }
+                       }
+               }
+       }
+
+       if (!newuseremail_ok) {
+               cprintf("%d You don't have permission to author messages as '%s'.\n",
+                       ERROR + HIGHER_ACCESS_REQUIRED,
+                       newuseremail
+                       );
+               return;
+       }
+
+       CCC->cs_flags |= CS_POSTING;
+
+       /* In mailbox rooms we have to behave a little differently --
+        * make sure the user has specified at least one recipient.  Then
+        * validate the recipient(s).  We do this for the Mail> room, as
+        * well as any room which has the "Mailbox" view set - unless it
+        * is the DRAFTS room which does not require recipients
+        */
+
+       if ( (  ( (CCC->room.QRflags & QR_MAILBOX) && (!strcasecmp(&CCC->room.QRname[11], MAILROOM)) )
+               || ( (CCC->room.QRflags & QR_MAILBOX) && (CCC->curr_view == VIEW_MAILBOX) )
+                    ) && (strcasecmp(&CCC->room.QRname[11], USERDRAFTROOM)) !=0 ) {
+               if (CCC->user.axlevel < AxProbU) {
+                       strcpy(recp, "sysop");
+                       strcpy(cc, "");
+                       strcpy(bcc, "");
+               }
+
+               valid_to = validate_recipients(recp, NULL, 0);
+               if (valid_to->num_error > 0) {
+                       cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_to->errormsg);
+                       free_recipients(valid_to);
+                       return;
+               }
+
+               valid_cc = validate_recipients(cc, NULL, 0);
+               if (valid_cc->num_error > 0) {
+                       cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_cc->errormsg);
+                       free_recipients(valid_to);
+                       free_recipients(valid_cc);
+                       return;
+               }
+
+               valid_bcc = validate_recipients(bcc, NULL, 0);
+               if (valid_bcc->num_error > 0) {
+                       cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_bcc->errormsg);
+                       free_recipients(valid_to);
+                       free_recipients(valid_cc);
+                       free_recipients(valid_bcc);
+                       return;
+               }
+
+               /* Recipient required, but none were specified */
+               if ( (valid_to->num_error < 0) && (valid_cc->num_error < 0) && (valid_bcc->num_error < 0) ) {
+                       free_recipients(valid_to);
+                       free_recipients(valid_cc);
+                       free_recipients(valid_bcc);
+                       cprintf("%d At least one recipient is required.\n", ERROR + NO_SUCH_USER);
+                       return;
+               }
+
+               if (valid_to->num_internet + valid_cc->num_internet + valid_bcc->num_internet > 0) {
+                       if (CtdlCheckInternetMailPermission(&CCC->user)==0) {
+                               cprintf("%d You do not have permission "
+                                       "to send Internet mail.\n",
+                                       ERROR + HIGHER_ACCESS_REQUIRED);
+                               free_recipients(valid_to);
+                               free_recipients(valid_cc);
+                               free_recipients(valid_bcc);
+                               return;
+                       }
+               }
+
+               if ( ( (valid_to->num_internet + valid_to->num_ignet + valid_cc->num_internet + valid_cc->num_ignet + valid_bcc->num_internet + valid_bcc->num_ignet) > 0)
+                    && (CCC->user.axlevel < AxNetU) ) {
+                       cprintf("%d Higher access required for network mail.\n",
+                               ERROR + HIGHER_ACCESS_REQUIRED);
+                       free_recipients(valid_to);
+                       free_recipients(valid_cc);
+                       free_recipients(valid_bcc);
+                       return;
+               }
+       
+               if ((RESTRICT_INTERNET == 1)
+                   && (valid_to->num_internet + valid_cc->num_internet + valid_bcc->num_internet > 0)
+                   && ((CCC->user.flags & US_INTERNET) == 0)
+                   && (!CCC->internal_pgm)) {
+                       cprintf("%d You don't have access to Internet mail.\n",
+                               ERROR + HIGHER_ACCESS_REQUIRED);
+                       free_recipients(valid_to);
+                       free_recipients(valid_cc);
+                       free_recipients(valid_bcc);
+                       return;
+               }
+
+       }
+
+       /* Is this a room which has anonymous-only or anonymous-option? */
+       anonymous = MES_NORMAL;
+       if (CCC->room.QRflags & QR_ANONONLY) {
+               anonymous = MES_ANONONLY;
+       }
+       if (CCC->room.QRflags & QR_ANONOPT) {
+               if (anon_flag == 1) {   /* only if the user requested it */
+                       anonymous = MES_ANONOPT;
+               }
+       }
+
+       if ((CCC->room.QRflags & QR_MAILBOX) == 0) {
+               recp[0] = 0;
+       }
+
+       /* Recommend to the client that the use of a message subject is
+        * strongly recommended in this room, if either the SUBJECTREQ flag
+        * is set, or if there is one or more Internet email recipients.
+        */
+       if (CCC->room.QRflags2 & QR2_SUBJECTREQ) subject_required = 1;
+       if ((valid_to)  && (valid_to->num_internet > 0))        subject_required = 1;
+       if ((valid_cc)  && (valid_cc->num_internet > 0))        subject_required = 1;
+       if ((valid_bcc) && (valid_bcc->num_internet > 0))       subject_required = 1;
+
+       /* If we're only checking the validity of the request, return
+        * success without creating the message.
+        */
+       if (post == 0) {
+               cprintf("%d %s|%d\n", CIT_OK,
+                       ((valid_to != NULL) ? valid_to->display_recp : ""), 
+                       subject_required);
+               free_recipients(valid_to);
+               free_recipients(valid_cc);
+               free_recipients(valid_bcc);
+               return;
+       }
+
+       /* We don't need these anymore because we'll do it differently below */
+       free_recipients(valid_to);
+       free_recipients(valid_cc);
+       free_recipients(valid_bcc);
+
+       /* Read in the message from the client. */
+       if (do_confirm) {
+               cprintf("%d send message\n", START_CHAT_MODE);
+       } else {
+               cprintf("%d send message\n", SEND_LISTING);
+       }
+
+       msg = CtdlMakeMessage(&CCC->user, recp, cc,
+                             CCC->room.QRname, anonymous, format_type,
+                             newusername, newuseremail, subject,
+                             ((!IsEmptyStr(supplied_euid)) ? supplied_euid : NULL),
+                             NULL, references);
+
+       /* Put together one big recipients struct containing to/cc/bcc all in
+        * one.  This is for the envelope.
+        */
+       char *all_recps = malloc(SIZ * 3);
+       strcpy(all_recps, recp);
+       if (!IsEmptyStr(cc)) {
+               if (!IsEmptyStr(all_recps)) {
+                       strcat(all_recps, ",");
+               }
+               strcat(all_recps, cc);
+       }
+       if (!IsEmptyStr(bcc)) {
+               if (!IsEmptyStr(all_recps)) {
+                       strcat(all_recps, ",");
+               }
+               strcat(all_recps, bcc);
+       }
+       if (!IsEmptyStr(all_recps)) {
+               valid = validate_recipients(all_recps, NULL, 0);
+       }
+       else {
+               valid = NULL;
+       }
+       free(all_recps);
+
+       if ((valid != NULL) && (valid->num_room == 1))
+       {
+               /* posting into an ML room? set the envelope from 
+                * to the actual mail address so others get a valid
+                * reply-to-header.
+                */
+               msg->cm_fields[eenVelopeTo] = strdup(valid->recp_orgroom);
+       }
+
+       if (msg != NULL) {
+               msgnum = CtdlSubmitMsg(msg, valid, "", QP_EADDR);
+               if (do_confirm) {
+                       cprintf("%ld\n", msgnum);
+
+                       if (StrLength(CCC->StatusMessage) > 0) {
+                               cprintf("%s\n", ChrPtr(CCC->StatusMessage));
+                       }
+                       else if (msgnum >= 0L) {
+                               client_write(HKEY("Message accepted.\n"));
+                       }
+                       else {
+                               client_write(HKEY("Internal error.\n"));
+                       }
+
+                       if (!CM_IsEmpty(msg, eExclusiveID)) {
+                               cprintf("%s\n", msg->cm_fields[eExclusiveID]);
+                       } else {
+                               cprintf("\n");
+                       }
+                       cprintf("000\n");
+               }
+
+               CM_Free(msg);
+       }
+       if (valid != NULL) {
+               free_recipients(valid);
+       }
+       return;
+}
+
+/*
+ * Delete message from current room
+ */
+void cmd_dele(char *args)
+{
+       int num_deleted;
+       int i;
+       char msgset[SIZ];
+       char msgtok[32];
+       long *msgs;
+       int num_msgs = 0;
+
+       extract_token(msgset, args, 0, '|', sizeof msgset);
+       num_msgs = num_tokens(msgset, ',');
+       if (num_msgs < 1) {
+               cprintf("%d Nothing to do.\n", CIT_OK);
+               return;
+       }
+
+       if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom() == 0) {
+               cprintf("%d Higher access required.\n",
+                       ERROR + HIGHER_ACCESS_REQUIRED);
+               return;
+       }
+
+       /*
+        * Build our message set to be moved/copied
+        */
+       msgs = malloc(num_msgs * sizeof(long));
+       for (i=0; i<num_msgs; ++i) {
+               extract_token(msgtok, msgset, i, ',', sizeof msgtok);
+               msgs[i] = atol(msgtok);
+       }
+
+       num_deleted = CtdlDeleteMessages(CC->room.QRname, msgs, num_msgs, "");
+       free(msgs);
+
+       if (num_deleted) {
+               cprintf("%d %d message%s deleted.\n", CIT_OK,
+                       num_deleted, ((num_deleted != 1) ? "s" : ""));
+       } else {
+               cprintf("%d Message not found.\n", ERROR + MESSAGE_NOT_FOUND);
+       }
+}
+
+
+
+/*
+ * move or copy a message to another room
+ */
+void cmd_move(char *args)
+{
+       char msgset[SIZ];
+       char msgtok[32];
+       long *msgs;
+       int num_msgs = 0;
+
+       char targ[ROOMNAMELEN];
+       struct ctdlroom qtemp;
+       int err;
+       int is_copy = 0;
+       int ra;
+       int permit = 0;
+       int i;
+
+       extract_token(msgset, args, 0, '|', sizeof msgset);
+       num_msgs = num_tokens(msgset, ',');
+       if (num_msgs < 1) {
+               cprintf("%d Nothing to do.\n", CIT_OK);
+               return;
+       }
+
+       extract_token(targ, args, 1, '|', sizeof targ);
+       convert_room_name_macros(targ, sizeof targ);
+       targ[ROOMNAMELEN - 1] = 0;
+       is_copy = extract_int(args, 2);
+
+       if (CtdlGetRoom(&qtemp, targ) != 0) {
+               cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, targ);
+               return;
+       }
+
+       if (!strcasecmp(qtemp.QRname, CC->room.QRname)) {
+               cprintf("%d Source and target rooms are the same.\n", ERROR + ALREADY_EXISTS);
+               return;
+       }
+
+       CtdlGetUser(&CC->user, CC->curr_user);
+       CtdlRoomAccess(&qtemp, &CC->user, &ra, NULL);
+
+       /* Check for permission to perform this operation.
+        * Remember: "CC->room" is source, "qtemp" is target.
+        */
+       permit = 0;
+
+       /* Admins can move/copy */
+       if (CC->user.axlevel >= AxAideU) permit = 1;
+
+       /* Room aides can move/copy */
+       if (CC->user.usernum == CC->room.QRroomaide) permit = 1;
+
+       /* Permit move/copy from personal rooms */
+       if ((CC->room.QRflags & QR_MAILBOX)
+           && (qtemp.QRflags & QR_MAILBOX)) permit = 1;
+
+       /* Permit only copy from public to personal room */
+       if ( (is_copy)
+            && (!(CC->room.QRflags & QR_MAILBOX))
+            && (qtemp.QRflags & QR_MAILBOX)) permit = 1;
+
+       /* Permit message removal from collaborative delete rooms */
+       if (CC->room.QRflags2 & QR2_COLLABDEL) permit = 1;
+
+       /* Users allowed to post into the target room may move into it too. */
+       if ((CC->room.QRflags & QR_MAILBOX) && 
+           (qtemp.QRflags & UA_POSTALLOWED))  permit = 1;
+
+       /* User must have access to target room */
+       if (!(ra & UA_KNOWN))  permit = 0;
+
+       if (!permit) {
+               cprintf("%d Higher access required.\n",
+                       ERROR + HIGHER_ACCESS_REQUIRED);
+               return;
+       }
+
+       /*
+        * Build our message set to be moved/copied
+        */
+       msgs = malloc(num_msgs * sizeof(long));
+       for (i=0; i<num_msgs; ++i) {
+               extract_token(msgtok, msgset, i, ',', sizeof msgtok);
+               msgs[i] = atol(msgtok);
+       }
+
+       /*
+        * Do the copy
+        */
+       err = CtdlSaveMsgPointersInRoom(targ, msgs, num_msgs, 1, NULL, 0);
+       if (err != 0) {
+               cprintf("%d Cannot store message(s) in %s: error %d\n",
+                       err, targ, err);
+               free(msgs);
+               return;
+       }
+
+       /* Now delete the message from the source room,
+        * if this is a 'move' rather than a 'copy' operation.
+        */
+       if (is_copy == 0) {
+               CtdlDeleteMessages(CC->room.QRname, msgs, num_msgs, "");
+       }
+       free(msgs);
+
+       cprintf("%d Message(s) %s.\n", CIT_OK, (is_copy ? "copied" : "moved") );
+}
+
+
+/*****************************************************************************/
+/*                      MODULE INITIALIZATION STUFF                          */
+/*****************************************************************************/
+CTDL_MODULE_INIT(ctdl_message)
+{
+       if (!threading) {
+
+               CtdlRegisterProtoHook(cmd_msgs, "MSGS", "Output a list of messages in the current room");
+               CtdlRegisterProtoHook(cmd_msg0, "MSG0", "Output a message in plain text format");
+               CtdlRegisterProtoHook(cmd_msg2, "MSG2", "Output a message in RFC822 format");
+               CtdlRegisterProtoHook(cmd_msg3, "MSG3", "Output a message in raw format (deprecated)");
+               CtdlRegisterProtoHook(cmd_msg4, "MSG4", "Output a message in the client's preferred format");
+               CtdlRegisterProtoHook(cmd_msgp, "MSGP", "Select preferred format for MSG4 output");
+               CtdlRegisterProtoHook(cmd_opna, "OPNA", "Open an attachment for download");
+               CtdlRegisterProtoHook(cmd_dlat, "DLAT", "Download an attachment");
+               CtdlRegisterProtoHook(cmd_ent0, "ENT0", "Enter a message");
+               CtdlRegisterProtoHook(cmd_dele, "DELE", "Delete a message");
+               CtdlRegisterProtoHook(cmd_move, "MOVE", "Move or copy a message to another room");
+       }
+
+        /* return our Subversion id for the Log */
+       return "ctdl_message";
+}
index 398f1eb0f864b5b420f48fb401d4f4abb4c4bf3a..724ee0f941cb20f73cfc1f0609ed6837c8af4256 100644 (file)
@@ -97,8 +97,10 @@ void cdb_verbose_log(const DB_ENV *dbenv, const char *msg)
 /* Verbose logging callback */
 void cdb_verbose_err(const DB_ENV *dbenv, const char *errpfx, const char *msg)
 {
+       int *FOO = NULL;
        syslog(LOG_ALERT, "DB: %s", msg);
        cit_backtrace();
+       *FOO = 1;
 }
 
 
index dbc89adaa6c8153cade0153a8cfbf74780b88632..f103de2d4529a830456a2c3ae8e47e6cb7fcc8ef 100644 (file)
@@ -162,10 +162,10 @@ void rebuild_euid_index_for_msg(long msgnum, void *userdata) {
 
        msg = CtdlFetchMessage(msgnum, 0);
        if (msg == NULL) return;
-       if (msg->cm_fields['E'] != NULL) {
-               index_message_by_euid(msg->cm_fields['E'], &CC->room, msgnum);
+       if (!CM_IsEmpty(msg, eExclusiveID)) {
+               index_message_by_euid(msg->cm_fields[eExclusiveID], &CC->room, msgnum);
        }
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
index 108410af29a79a7924526d2f214ba5dea868ffea..077b509300c002433aa5f21cd9a26d9f84b6d689 100644 (file)
@@ -49,6 +49,7 @@
 #include "room_ops.h"
 #include "database.h"
 #include "msgbase.h"
+#include "internet_addressing.h"
 #include "journaling.h"
 
 #include "ctdl_module.h"
index 3cab315e19a02e9e49e9d895655a217c12eba27a..8950a47ed9800b48f29743199d028c5fe00e6408 100644 (file)
@@ -528,9 +528,6 @@ void CtdlUserLogout(void);
 /*
  * Expose API calls from msgbase.c
  */
-char *CtdlGetSysConfig(char *sysconfname);
-void CtdlPutSysConfig(char *sysconfname, char *sysconfdata);
-
 
 
 
index 3237007d60a27d6a06d8153697f972049c49490b..a1b0a37e176c84748abdb35f90d6202a5b2a5720 100644 (file)
@@ -326,8 +326,637 @@ int CtdlHostAlias(char *fqdn) {
 
 
 
+/*
+ * Determine whether a given Internet address belongs to the current user
+ */
+int CtdlIsMe(char *addr, int addr_buf_len)
+{
+       struct recptypes *recp;
+       int i;
+
+       recp = validate_recipients(addr, NULL, 0);
+       if (recp == NULL) return(0);
+
+       if (recp->num_local == 0) {
+               free_recipients(recp);
+               return(0);
+       }
+
+       for (i=0; i<recp->num_local; ++i) {
+               extract_token(addr, recp->recp_local, i, '|', addr_buf_len);
+               if (!strcasecmp(addr, CC->user.fullname)) {
+                       free_recipients(recp);
+                       return(1);
+               }
+       }
+
+       free_recipients(recp);
+       return(0);
+}
+
+
+/*
+ * Citadel protocol command to do the same
+ */
+void cmd_isme(char *argbuf) {
+       char addr[256];
+
+       if (CtdlAccessCheck(ac_logged_in)) return;
+       extract_token(addr, argbuf, 0, '|', sizeof addr);
+
+       if (CtdlIsMe(addr, sizeof addr)) {
+               cprintf("%d %s\n", CIT_OK, addr);
+       }
+       else {
+               cprintf("%d Not you.\n", ERROR + ILLEGAL_VALUE);
+       }
+
+}
+
+
+/* If the last item in a list of recipients was truncated to a partial address,
+ * remove it completely in order to avoid choking libSieve
+ */
+void sanitize_truncated_recipient(char *str)
+{
+       if (!str) return;
+       if (num_tokens(str, ',') < 2) return;
+
+       int len = strlen(str);
+       if (len < 900) return;
+       if (len > 998) str[998] = 0;
+
+       char *cptr = strrchr(str, ',');
+       if (!cptr) return;
+
+       char *lptr = strchr(cptr, '<');
+       char *rptr = strchr(cptr, '>');
+
+       if ( (lptr) && (rptr) && (rptr > lptr) ) return;
+
+       *cptr = 0;
+}
+
+
+
+
+
+/*
+ * This function is self explanatory.
+ * (What can I say, I'm in a weird mood today...)
+ */
+void remove_any_whitespace_to_the_left_or_right_of_at_symbol(char *name)
+{
+       int i;
+
+       for (i = 0; i < strlen(name); ++i) {
+               if (name[i] == '@') {
+                       while (isspace(name[i - 1]) && i > 0) {
+                               strcpy(&name[i - 1], &name[i]);
+                               --i;
+                       }
+                       while (isspace(name[i + 1])) {
+                               strcpy(&name[i + 1], &name[i + 2]);
+                       }
+               }
+       }
+}
 
 
+/*
+ * Aliasing for network mail.
+ * (Error messages have been commented out, because this is a server.)
+ */
+int alias(char *name)
+{                              /* process alias and routing info for mail */
+       struct CitContext *CCC = CC;
+       FILE *fp;
+       int a, i;
+       char aaa[SIZ], bbb[SIZ];
+       char *ignetcfg = NULL;
+       char *ignetmap = NULL;
+       int at = 0;
+       char node[64];
+       char testnode[64];
+       char buf[SIZ];
+
+       char original_name[256];
+       safestrncpy(original_name, name, sizeof original_name);
+
+       striplt(name);
+       remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
+       stripallbut(name, '<', '>');
+
+       fp = fopen(file_mail_aliases, "r");
+       if (fp == NULL) {
+               fp = fopen("/dev/null", "r");
+       }
+       if (fp == NULL) {
+               return (MES_ERROR);
+       }
+       strcpy(aaa, "");
+       strcpy(bbb, "");
+       while (fgets(aaa, sizeof aaa, fp) != NULL) {
+               while (isspace(name[0]))
+                       strcpy(name, &name[1]);
+               aaa[strlen(aaa) - 1] = 0;
+               strcpy(bbb, "");
+               for (a = 0; a < strlen(aaa); ++a) {
+                       if (aaa[a] == ',') {
+                               strcpy(bbb, &aaa[a + 1]);
+                               aaa[a] = 0;
+                       }
+               }
+               if (!strcasecmp(name, aaa))
+                       strcpy(name, bbb);
+       }
+       fclose(fp);
+
+       /* Hit the Global Address Book */
+       if (CtdlDirectoryLookup(aaa, name, sizeof aaa) == 0) {
+               strcpy(name, aaa);
+       }
+
+       if (strcasecmp(original_name, name)) {
+               MSG_syslog(LOG_INFO, "%s is being forwarded to %s\n", original_name, name);
+       }
+
+       /* Change "user @ xxx" to "user" if xxx is an alias for this host */
+       for (a=0; a<strlen(name); ++a) {
+               if (name[a] == '@') {
+                       if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) {
+                               name[a] = 0;
+                               MSG_syslog(LOG_INFO, "Changed to <%s>\n", name);
+                       }
+               }
+       }
+
+       /* determine local or remote type, see citadel.h */
+       at = haschar(name, '@');
+       if (at == 0) return(MES_LOCAL);         /* no @'s - local address */
+       if (at > 1) return(MES_ERROR);          /* >1 @'s - invalid address */
+       remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
+
+       /* figure out the delivery mode */
+       extract_token(node, name, 1, '@', sizeof node);
+
+       /* If there are one or more dots in the nodename, we assume that it
+        * is an FQDN and will attempt SMTP delivery to the Internet.
+        */
+       if (haschar(node, '.') > 0) {
+               return(MES_INTERNET);
+       }
+
+       /* Otherwise we look in the IGnet maps for a valid Citadel node.
+        * Try directly-connected nodes first...
+        */
+       ignetcfg = CtdlGetSysConfig(IGNETCFG);
+       for (i=0; i<num_tokens(ignetcfg, '\n'); ++i) {
+               extract_token(buf, ignetcfg, i, '\n', sizeof buf);
+               extract_token(testnode, buf, 0, '|', sizeof testnode);
+               if (!strcasecmp(node, testnode)) {
+                       free(ignetcfg);
+                       return(MES_IGNET);
+               }
+       }
+       free(ignetcfg);
+
+       /*
+        * Then try nodes that are two or more hops away.
+        */
+       ignetmap = CtdlGetSysConfig(IGNETMAP);
+       for (i=0; i<num_tokens(ignetmap, '\n'); ++i) {
+               extract_token(buf, ignetmap, i, '\n', sizeof buf);
+               extract_token(testnode, buf, 0, '|', sizeof testnode);
+               if (!strcasecmp(node, testnode)) {
+                       free(ignetmap);
+                       return(MES_IGNET);
+               }
+       }
+       free(ignetmap);
+
+       /* If we get to this point it's an invalid node name */
+       return (MES_ERROR);
+}
+
+
+
+/*
+ * Validate recipients, count delivery types and errors, and handle aliasing
+ * FIXME check for dupes!!!!!
+ *
+ * Returns 0 if all addresses are ok, ret->num_error = -1 if no addresses 
+ * were specified, or the number of addresses found invalid.
+ *
+ * Caller needs to free the result using free_recipients()
+ */
+struct recptypes *validate_recipients(const char *supplied_recipients, 
+                                     const char *RemoteIdentifier, 
+                                     int Flags) {
+       struct CitContext *CCC = CC;
+       struct recptypes *ret;
+       char *recipients = NULL;
+       char *org_recp;
+       char this_recp[256];
+       char this_recp_cooked[256];
+       char append[SIZ];
+       long len;
+       int num_recps = 0;
+       int i, j;
+       int mailtype;
+       int invalid;
+       struct ctdluser tempUS;
+       struct ctdlroom tempQR;
+       struct ctdlroom tempQR2;
+       int err = 0;
+       char errmsg[SIZ];
+       int in_quotes = 0;
+
+       /* Initialize */
+       ret = (struct recptypes *) malloc(sizeof(struct recptypes));
+       if (ret == NULL) return(NULL);
+
+       /* Set all strings to null and numeric values to zero */
+       memset(ret, 0, sizeof(struct recptypes));
+
+       if (supplied_recipients == NULL) {
+               recipients = strdup("");
+       }
+       else {
+               recipients = strdup(supplied_recipients);
+       }
+
+       /* Allocate some memory.  Yes, this allocates 500% more memory than we will
+        * actually need, but it's healthier for the heap than doing lots of tiny
+        * realloc() calls instead.
+        */
+       len = strlen(recipients) + 1024;
+       ret->errormsg = malloc(len);
+       ret->recp_local = malloc(len);
+       ret->recp_internet = malloc(len);
+       ret->recp_ignet = malloc(len);
+       ret->recp_room = malloc(len);
+       ret->display_recp = malloc(len);
+       ret->recp_orgroom = malloc(len);
+       org_recp = malloc(len);
+
+       ret->errormsg[0] = 0;
+       ret->recp_local[0] = 0;
+       ret->recp_internet[0] = 0;
+       ret->recp_ignet[0] = 0;
+       ret->recp_room[0] = 0;
+       ret->recp_orgroom[0] = 0;
+       ret->display_recp[0] = 0;
+
+       ret->recptypes_magic = RECPTYPES_MAGIC;
+
+       /* Change all valid separator characters to commas */
+       for (i=0; !IsEmptyStr(&recipients[i]); ++i) {
+               if ((recipients[i] == ';') || (recipients[i] == '|')) {
+                       recipients[i] = ',';
+               }
+       }
+
+       /* Now start extracting recipients... */
+
+       while (!IsEmptyStr(recipients)) {
+               for (i=0; i<=strlen(recipients); ++i) {
+                       if (recipients[i] == '\"') in_quotes = 1 - in_quotes;
+                       if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) {
+                               safestrncpy(this_recp, recipients, i+1);
+                               this_recp[i] = 0;
+                               if (recipients[i] == ',') {
+                                       strcpy(recipients, &recipients[i+1]);
+                               }
+                               else {
+                                       strcpy(recipients, "");
+                               }
+                               break;
+                       }
+               }
+
+               striplt(this_recp);
+               if (IsEmptyStr(this_recp))
+                       break;
+               MSG_syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp);
+               ++num_recps;
+
+               strcpy(org_recp, this_recp);
+               alias(this_recp);
+               alias(this_recp);
+               mailtype = alias(this_recp);
+
+               for (j = 0; !IsEmptyStr(&this_recp[j]); ++j) {
+                       if (this_recp[j]=='_') {
+                               this_recp_cooked[j] = ' ';
+                       }
+                       else {
+                               this_recp_cooked[j] = this_recp[j];
+                       }
+               }
+               this_recp_cooked[j] = '\0';
+               invalid = 0;
+               errmsg[0] = 0;
+               switch(mailtype) {
+               case MES_LOCAL:
+                       if (!strcasecmp(this_recp, "sysop")) {
+                               ++ret->num_room;
+                               strcpy(this_recp, config.c_aideroom);
+                               if (!IsEmptyStr(ret->recp_room)) {
+                                       strcat(ret->recp_room, "|");
+                               }
+                               strcat(ret->recp_room, this_recp);
+                       }
+                       else if ( (!strncasecmp(this_recp, "room_", 5))
+                                 && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) {
+
+                               /* Save room so we can restore it later */
+                               tempQR2 = CCC->room;
+                               CCC->room = tempQR;
+                                       
+                               /* Check permissions to send mail to this room */
+                               err = CtdlDoIHavePermissionToPostInThisRoom(
+                                       errmsg, 
+                                       sizeof errmsg, 
+                                       RemoteIdentifier,
+                                       Flags,
+                                       0                       /* 0 = not a reply */
+                                       );
+                               if (err)
+                               {
+                                       ++ret->num_error;
+                                       invalid = 1;
+                               } 
+                               else {
+                                       ++ret->num_room;
+                                       if (!IsEmptyStr(ret->recp_room)) {
+                                               strcat(ret->recp_room, "|");
+                                       }
+                                       strcat(ret->recp_room, &this_recp_cooked[5]);
+
+                                       if (!IsEmptyStr(ret->recp_orgroom)) {
+                                               strcat(ret->recp_orgroom, "|");
+                                       }
+                                       strcat(ret->recp_orgroom, org_recp);
+
+                               }
+                                       
+                               /* Restore room in case something needs it */
+                               CCC->room = tempQR2;
+
+                       }
+                       else if (CtdlGetUser(&tempUS, this_recp) == 0) {
+                               ++ret->num_local;
+                               strcpy(this_recp, tempUS.fullname);
+                               if (!IsEmptyStr(ret->recp_local)) {
+                                       strcat(ret->recp_local, "|");
+                               }
+                               strcat(ret->recp_local, this_recp);
+                       }
+                       else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) {
+                               ++ret->num_local;
+                               strcpy(this_recp, tempUS.fullname);
+                               if (!IsEmptyStr(ret->recp_local)) {
+                                       strcat(ret->recp_local, "|");
+                               }
+                               strcat(ret->recp_local, this_recp);
+                       }
+                       else {
+                               ++ret->num_error;
+                               invalid = 1;
+                       }
+                       break;
+               case MES_INTERNET:
+                       /* Yes, you're reading this correctly: if the target
+                        * domain points back to the local system or an attached
+                        * Citadel directory, the address is invalid.  That's
+                        * because if the address were valid, we would have
+                        * already translated it to a local address by now.
+                        */
+                       if (IsDirectory(this_recp, 0)) {
+                               ++ret->num_error;
+                               invalid = 1;
+                       }
+                       else {
+                               ++ret->num_internet;
+                               if (!IsEmptyStr(ret->recp_internet)) {
+                                       strcat(ret->recp_internet, "|");
+                               }
+                               strcat(ret->recp_internet, this_recp);
+                       }
+                       break;
+               case MES_IGNET:
+                       ++ret->num_ignet;
+                       if (!IsEmptyStr(ret->recp_ignet)) {
+                               strcat(ret->recp_ignet, "|");
+                       }
+                       strcat(ret->recp_ignet, this_recp);
+                       break;
+               case MES_ERROR:
+                       ++ret->num_error;
+                       invalid = 1;
+                       break;
+               }
+               if (invalid) {
+                       if (IsEmptyStr(errmsg)) {
+                               snprintf(append, sizeof append, "Invalid recipient: %s", this_recp);
+                       }
+                       else {
+                               snprintf(append, sizeof append, "%s", errmsg);
+                       }
+                       if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) {
+                               if (!IsEmptyStr(ret->errormsg)) {
+                                       strcat(ret->errormsg, "; ");
+                               }
+                               strcat(ret->errormsg, append);
+                       }
+               }
+               else {
+                       if (IsEmptyStr(ret->display_recp)) {
+                               strcpy(append, this_recp);
+                       }
+                       else {
+                               snprintf(append, sizeof append, ", %s", this_recp);
+                       }
+                       if ( (strlen(ret->display_recp)+strlen(append)) < SIZ) {
+                               strcat(ret->display_recp, append);
+                       }
+               }
+       }
+       free(org_recp);
+
+       if ((ret->num_local + ret->num_internet + ret->num_ignet +
+            ret->num_room + ret->num_error) == 0) {
+               ret->num_error = (-1);
+               strcpy(ret->errormsg, "No recipients specified.");
+       }
+
+       MSGM_syslog(LOG_DEBUG, "validate_recipients()\n");
+       MSG_syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local);
+       MSG_syslog(LOG_DEBUG, "  room: %d <%s>\n", ret->num_room, ret->recp_room);
+       MSG_syslog(LOG_DEBUG, "  inet: %d <%s>\n", ret->num_internet, ret->recp_internet);
+       MSG_syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet);
+       MSG_syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg);
+
+       free(recipients);
+       return(ret);
+}
+
+
+/*
+ * Destructor for struct recptypes
+ */
+void free_recipients(struct recptypes *valid) {
+
+       if (valid == NULL) {
+               return;
+       }
+
+       if (valid->recptypes_magic != RECPTYPES_MAGIC) {
+               struct CitContext *CCC = CC;
+               MSGM_syslog(LOG_EMERG, "Attempt to call free_recipients() on some other data type!\n");
+               abort();
+       }
+
+       if (valid->errormsg != NULL)            free(valid->errormsg);
+       if (valid->recp_local != NULL)          free(valid->recp_local);
+       if (valid->recp_internet != NULL)       free(valid->recp_internet);
+       if (valid->recp_ignet != NULL)          free(valid->recp_ignet);
+       if (valid->recp_room != NULL)           free(valid->recp_room);
+       if (valid->recp_orgroom != NULL)        free(valid->recp_orgroom);
+       if (valid->display_recp != NULL)        free(valid->display_recp);
+       if (valid->bounce_to != NULL)           free(valid->bounce_to);
+       if (valid->envelope_from != NULL)       free(valid->envelope_from);
+       if (valid->sending_room != NULL)        free(valid->sending_room);
+       free(valid);
+}
+
+
+char *qp_encode_email_addrs(char *source)
+{
+       struct CitContext *CCC = CC;
+       char *user, *node, *name;
+       const char headerStr[] = "=?UTF-8?Q?";
+       char *Encoded;
+       char *EncodedName;
+       char *nPtr;
+       int need_to_encode = 0;
+       long SourceLen;
+       long EncodedMaxLen;
+       long nColons = 0;
+       long *AddrPtr;
+       long *AddrUtf8;
+       long nAddrPtrMax = 50;
+       long nmax;
+       int InQuotes = 0;
+       int i, n;
+
+       if (source == NULL) return source;
+       if (IsEmptyStr(source)) return source;
+       if (MessageDebugEnabled != 0) cit_backtrace();
+       MSG_syslog(LOG_DEBUG, "qp_encode_email_addrs: [%s]\n", source);
+
+       AddrPtr = malloc (sizeof (long) * nAddrPtrMax);
+       AddrUtf8 = malloc (sizeof (long) * nAddrPtrMax);
+       memset(AddrUtf8, 0, sizeof (long) * nAddrPtrMax);
+       *AddrPtr = 0;
+       i = 0;
+       while (!IsEmptyStr (&source[i])) {
+               if (nColons >= nAddrPtrMax){
+                       long *ptr;
+
+                       ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2);
+                       memcpy (ptr, AddrPtr, sizeof (long) * nAddrPtrMax);
+                       free (AddrPtr), AddrPtr = ptr;
+
+                       ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2);
+                       memset(&ptr[nAddrPtrMax], 0, 
+                              sizeof (long) * nAddrPtrMax);
+
+                       memcpy (ptr, AddrUtf8, sizeof (long) * nAddrPtrMax);
+                       free (AddrUtf8), AddrUtf8 = ptr;
+                       nAddrPtrMax *= 2;                               
+               }
+               if (((unsigned char) source[i] < 32) || 
+                   ((unsigned char) source[i] > 126)) {
+                       need_to_encode = 1;
+                       AddrUtf8[nColons] = 1;
+               }
+               if (source[i] == '"')
+                       InQuotes = !InQuotes;
+               if (!InQuotes && source[i] == ',') {
+                       AddrPtr[nColons] = i;
+                       nColons++;
+               }
+               i++;
+       }
+       if (need_to_encode == 0) {
+               free(AddrPtr);
+               free(AddrUtf8);
+               return source;
+       }
+
+       SourceLen = i;
+       EncodedMaxLen = nColons * (sizeof(headerStr) + 3) + SourceLen * 3;
+       Encoded = (char*) malloc (EncodedMaxLen);
+
+       for (i = 0; i < nColons; i++)
+               source[AddrPtr[i]++] = '\0';
+       /* TODO: if libidn, this might get larger*/
+       user = malloc(SourceLen + 1);
+       node = malloc(SourceLen + 1);
+       name = malloc(SourceLen + 1);
+
+       nPtr = Encoded;
+       *nPtr = '\0';
+       for (i = 0; i < nColons && nPtr != NULL; i++) {
+               nmax = EncodedMaxLen - (nPtr - Encoded);
+               if (AddrUtf8[i]) {
+                       process_rfc822_addr(&source[AddrPtr[i]], 
+                                           user,
+                                           node,
+                                           name);
+                       /* TODO: libIDN here ! */
+                       if (IsEmptyStr(name)) {
+                               n = snprintf(nPtr, nmax, 
+                                            (i==0)?"%s@%s" : ",%s@%s",
+                                            user, node);
+                       }
+                       else {
+                               EncodedName = rfc2047encode(name, strlen(name));                        
+                               n = snprintf(nPtr, nmax, 
+                                            (i==0)?"%s <%s@%s>" : ",%s <%s@%s>",
+                                            EncodedName, user, node);
+                               free(EncodedName);
+                       }
+               }
+               else { 
+                       n = snprintf(nPtr, nmax, 
+                                    (i==0)?"%s" : ",%s",
+                                    &source[AddrPtr[i]]);
+               }
+               if (n > 0 )
+                       nPtr += n;
+               else { 
+                       char *ptr, *nnPtr;
+                       ptr = (char*) malloc(EncodedMaxLen * 2);
+                       memcpy(ptr, Encoded, EncodedMaxLen);
+                       nnPtr = ptr + (nPtr - Encoded), nPtr = nnPtr;
+                       free(Encoded), Encoded = ptr;
+                       EncodedMaxLen *= 2;
+                       i--; /* do it once more with properly lengthened buffer */
+               }
+       }
+       for (i = 0; i < nColons; i++)
+               source[--AddrPtr[i]] = ',';
+
+       free(user);
+       free(node);
+       free(name);
+       free(AddrUtf8);
+       free(AddrPtr);
+       return Encoded;
+}
 
 
 /*
@@ -553,7 +1182,6 @@ int convert_field(struct CtdlMessage *msg, const char *beg, const char *end) {
        int i;
        const char *colonpos = NULL;
        int processed = 0;
-       char buf[SIZ];
        char user[1024];
        char node[1024];
        char name[1024];
@@ -589,100 +1217,100 @@ int convert_field(struct CtdlMessage *msg, const char *beg, const char *end) {
        if (!strcasecmp(key, "Date")) {
                parsed_date = parsedate(value);
                if (parsed_date < 0L) parsed_date = time(NULL);
-               snprintf(buf, sizeof buf, "%ld", (long)parsed_date );
-               if (msg->cm_fields['T'] == NULL)
-                       msg->cm_fields['T'] = strdup(buf);
+
+               if (CM_IsEmpty(msg, eTimestamp))
+                       CM_SetFieldLONG(msg, eTimestamp, parsed_date);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "From")) {
                process_rfc822_addr(value, user, node, name);
                syslog(LOG_DEBUG, "Converted to <%s@%s> (%s)\n", user, node, name);
-               snprintf(addr, sizeof addr, "%s@%s", user, node);
-               if (msg->cm_fields['A'] == NULL)
-                       msg->cm_fields['A'] = strdup(name);
-               if (msg->cm_fields['F'] == NULL)
-                       msg->cm_fields['F'] = strdup(addr);
+               snprintf(addr, sizeof(addr), "%s@%s", user, node);
+               if (CM_IsEmpty(msg, eAuthor))
+                       CM_SetField(msg, eAuthor, name, strlen(name));
+               if (CM_IsEmpty(msg, erFc822Addr))
+                       CM_SetField(msg, erFc822Addr, addr, strlen(addr));
                processed = 1;
        }
 
        else if (!strcasecmp(key, "Subject")) {
-               if (msg->cm_fields['U'] == NULL)
-                       msg->cm_fields['U'] = strndup(value, valuelen);
+               if (CM_IsEmpty(msg, eMsgSubject))
+                       CM_SetField(msg, eMsgSubject, value, valuelen);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "List-ID")) {
-               if (msg->cm_fields['L'] == NULL)
-                       msg->cm_fields['L'] = strndup(value, valuelen);
+               if (CM_IsEmpty(msg, eListID))
+                       CM_SetField(msg, eListID, value, valuelen);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "To")) {
-               if (msg->cm_fields['R'] == NULL)
-                       msg->cm_fields['R'] = strndup(value, valuelen);
+               if (CM_IsEmpty(msg, eRecipient))
+                       CM_SetField(msg, eRecipient, value, valuelen);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "CC")) {
-               if (msg->cm_fields['Y'] == NULL)
-                       msg->cm_fields['Y'] = strndup(value, valuelen);
+               if (CM_IsEmpty(msg, eCarbonCopY))
+                       CM_SetField(msg, eCarbonCopY, value, valuelen);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "Message-ID")) {
-               if (msg->cm_fields['I'] != NULL) {
+               if (!CM_IsEmpty(msg, emessageId)) {
                        syslog(LOG_WARNING, "duplicate message id\n");
                }
+               else {
+                       char *pValue;
+                       long pValueLen;
 
-               if (msg->cm_fields['I'] == NULL) {
-                       msg->cm_fields['I'] = strndup(value, valuelen);
-
+                       pValue = value;
+                       pValueLen = valuelen;
                        /* Strip angle brackets */
-                       while (haschar(msg->cm_fields['I'], '<') > 0) {
-                               strcpy(&msg->cm_fields['I'][0],
-                                       &msg->cm_fields['I'][1]);
+                       while (haschar(pValue, '<') > 0) {
+                               pValue ++;
+                               pValueLen --;
                        }
-                       for (i = 0; i<strlen(msg->cm_fields['I']); ++i)
-                               if (msg->cm_fields['I'][i] == '>')
-                                       msg->cm_fields['I'][i] = 0;
+
+                       for (i = 0; i <= pValueLen; ++i)
+                               if (pValue[i] == '>') {
+                                       pValueLen = i;
+                                       break;
+                               }
+
+                       CM_SetField(msg, emessageId, pValue, pValueLen);
                }
 
                processed = 1;
        }
 
        else if (!strcasecmp(key, "Return-Path")) {
-               if (msg->cm_fields['P'] == NULL)
-                       msg->cm_fields['P'] = strndup(value, valuelen);
+               if (CM_IsEmpty(msg, eMessagePath))
+                       CM_SetField(msg, eMessagePath, value, valuelen);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "Envelope-To")) {
-               if (msg->cm_fields['V'] == NULL)
-                       msg->cm_fields['V'] = strndup(value, valuelen);
+               if (CM_IsEmpty(msg, eenVelopeTo))
+                       CM_SetField(msg, eenVelopeTo, value, valuelen);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "References")) {
-               if (msg->cm_fields['W'] != NULL) {
-                       free(msg->cm_fields['W']);
-               }
-               msg->cm_fields['W'] = strndup(value, valuelen);
+               CM_SetField(msg, eWeferences, value, valuelen);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "Reply-To")) {
-               if (msg->cm_fields['K'] != NULL) {
-                       free(msg->cm_fields['K']);
-               }
-               msg->cm_fields['K'] = strndup(value, valuelen);
+               CM_SetField(msg, eReplyTo, value, valuelen);
                processed = 1;
        }
 
        else if (!strcasecmp(key, "In-reply-to")) {
-               if (msg->cm_fields['W'] == NULL) {              /* References: supersedes In-reply-to: */
-                       msg->cm_fields['W'] = strndup(value, valuelen);
-               }
+               if (CM_IsEmpty(msg, eWeferences)) /* References: supersedes In-reply-to: */
+                       CM_SetField(msg, eWeferences, value, valuelen);
                processed = 1;
        }
 
@@ -690,7 +1318,7 @@ int convert_field(struct CtdlMessage *msg, const char *beg, const char *end) {
 
        /* Clean up and move on. */
        free(key);      /* Don't free 'value', it's actually the same buffer */
-       return(processed);
+       return processed;
 }
 
 
@@ -732,7 +1360,7 @@ void convert_references_to_wefewences(char *str) {
 /*
  * Convert an RFC822 message (headers + body) to a CtdlMessage structure.
  * NOTE: the supplied buffer becomes part of the CtdlMessage structure, and
- * will be deallocated when CtdlFreeMessage() is called.  Therefore, the
+ * will be deallocated when CM_Free() is called.  Therefore, the
  * supplied buffer should be DEREFERENCED.  It should not be freed or used
  * again.
  */
@@ -749,7 +1377,6 @@ struct CtdlMessage *convert_internet_message_buf(StrBuf **rfc822)
        struct CtdlMessage *msg;
        const char *pos, *beg, *end, *totalend;
        int done, alldone = 0;
-       char buf[SIZ];
        int converted;
        StrBuf *OtherHeaders;
 
@@ -818,21 +1445,21 @@ struct CtdlMessage *convert_internet_message_buf(StrBuf **rfc822)
        if (pos < totalend)
                StrBufAppendBufPlain(OtherHeaders, pos, totalend - pos, 0);
        FreeStrBuf(rfc822);
-       msg->cm_fields['M'] = SmashStrBuf(&OtherHeaders);
+       CM_SetAsFieldSB(msg, eMesageText, &OtherHeaders);
 
        /* Follow-up sanity checks... */
 
        /* If there's no timestamp on this message, set it to now. */
-       if (msg->cm_fields['T'] == NULL) {
-               snprintf(buf, sizeof buf, "%ld", (long)time(NULL));
-               msg->cm_fields['T'] = strdup(buf);
+       if (CM_IsEmpty(msg, eTimestamp)) {
+               CM_SetFieldLONG(msg, eTimestamp, time(NULL));
        }
 
        /* If a W (references, or rather, Wefewences) field is present, we
         * have to convert it from RFC822 format to Citadel format.
         */
-       if (msg->cm_fields['W'] != NULL) {
-               convert_references_to_wefewences(msg->cm_fields['W']);
+       if (!CM_IsEmpty(msg, eWeferences)) {
+               /// todo: API!
+               convert_references_to_wefewences(msg->cm_fields[eWeferences]);
        }
 
        return msg;
@@ -1018,20 +1645,20 @@ char *harvest_collected_addresses(struct CtdlMessage *msg) {
        char user[256], node[256], name[256];
        int is_harvestable;
        int i, j, h;
-       int field = 0;
+       eMsgField field = 0;
 
        if (msg == NULL) return(NULL);
 
        is_harvestable = 1;
        strcpy(addr, "");       
-       if (msg->cm_fields['A'] != NULL) {
-               strcat(addr, msg->cm_fields['A']);
+       if (!CM_IsEmpty(msg, eAuthor)) {
+               strcat(addr, msg->cm_fields[eAuthor]);
        }
-       if (msg->cm_fields['F'] != NULL) {
+       if (!CM_IsEmpty(msg, erFc822Addr)) {
                strcat(addr, " <");
-               strcat(addr, msg->cm_fields['F']);
+               strcat(addr, msg->cm_fields[erFc822Addr]);
                strcat(addr, ">");
-               if (IsDirectory(msg->cm_fields['F'], 0)) {
+               if (IsDirectory(msg->cm_fields[erFc822Addr], 0)) {
                        is_harvestable = 0;
                }
        }
@@ -1047,10 +1674,10 @@ char *harvest_collected_addresses(struct CtdlMessage *msg) {
 
        /* Scan both the R (To) and Y (CC) fields */
        for (i = 0; i < 2; ++i) {
-               if (i == 0) field = 'R' ;
-               if (i == 1) field = 'Y' ;
+               if (i == 0) field = eRecipient;
+               if (i == 1) field = eCarbonCopY;
 
-               if (msg->cm_fields[field] != NULL) {
+               if (!CM_IsEmpty(msg, field)) {
                        for (j=0; j<num_tokens(msg->cm_fields[field], ','); ++j) {
                                extract_token(addr, msg->cm_fields[field], j, ',', sizeof addr);
                                if (strstr(addr, "=?") != NULL)
@@ -1076,3 +1703,12 @@ char *harvest_collected_addresses(struct CtdlMessage *msg) {
        }
        return(coll);
 }
+
+
+CTDL_MODULE_INIT(internet_addressing)
+{
+       if (!threading) {
+               CtdlRegisterProtoHook(cmd_isme, "ISME", "Determine whether an email address belongs to a user");
+       }
+       return "internet_addressing";
+}
index 706231e8317c9b9feaedb168f2c64632f4e19911..74e581883803cdb0e2b37ee3f71baed0cc1bcb07 100644 (file)
@@ -8,10 +8,42 @@ struct internet_address_list {
        char ial_name[SIZ];
 };
 
+/* Data structure returned by validate_recipients() */
+struct recptypes {
+       int recptypes_magic;
+        int num_local;
+        int num_internet;
+        int num_ignet;
+       int num_room;
+        int num_error;
+       char *errormsg;
+       char *recp_local;
+       char *recp_internet;
+       char *recp_ignet;
+       char *recp_room;
+       char *recp_orgroom;
+       char *display_recp;
+       char *bounce_to;
+       char *envelope_from;
+       char *sending_room;
+};
+
+#define RECPTYPES_MAGIC 0xfeeb
+
+struct recptypes *validate_recipients(const char *recipients,
+                                     const char *RemoteIdentifier, 
+                                     int Flags);
+
+void free_recipients(struct recptypes *);
+
 
 int fuzzy_match(struct ctdluser *us, char *matchstring);
 void process_rfc822_addr(const char *rfc822, char *user, char *node, char *name);
 char *rfc822_fetch_field(const char *rfc822, const char *fieldname);
+void sanitize_truncated_recipient(char *str);
+char *qp_encode_email_addrs(char *source);
+int alias (char *name);
+
 
 int IsDirectory(char *addr, int allow_masq_domains);
 void CtdlDirectoryInit(void);
index 6d68d08748b7e24aa70b3abade7e69c2514669f9..27cf0580c307d881f6c37d132cd65ae4309cacc4 100644 (file)
@@ -59,7 +59,7 @@ void JournalBackgroundSubmit(struct CtdlMessage *msg,
        struct jnlq *jptr = NULL;
 
        /* Avoid double journaling! */
-       if (msg->cm_fields['J'] != NULL) {
+       if (!CM_IsEmpty(msg, eJournal)) {
                FreeStrBuf(&saved_rfc822_version);
                return;
        }
@@ -71,11 +71,11 @@ void JournalBackgroundSubmit(struct CtdlMessage *msg,
        }
        memset(jptr, 0, sizeof(struct jnlq));
        if (recps != NULL) memcpy(&jptr->recps, recps, sizeof(struct recptypes));
-       if (msg->cm_fields['A'] != NULL) jptr->from = strdup(msg->cm_fields['A']);
-       if (msg->cm_fields['N'] != NULL) jptr->node = strdup(msg->cm_fields['N']);
-       if (msg->cm_fields['F'] != NULL) jptr->rfca = strdup(msg->cm_fields['F']);
-       if (msg->cm_fields['U'] != NULL) jptr->subj = strdup(msg->cm_fields['U']);
-       if (msg->cm_fields['I'] != NULL) jptr->msgn = strdup(msg->cm_fields['I']);
+       if (!CM_IsEmpty(msg, eAuthor)) jptr->from = strdup(msg->cm_fields[eAuthor]);
+       if (!CM_IsEmpty(msg, eNodeName)) jptr->node = strdup(msg->cm_fields[eNodeName]);
+       if (!CM_IsEmpty(msg, erFc822Addr)) jptr->rfca = strdup(msg->cm_fields[erFc822Addr]);
+       if (!CM_IsEmpty(msg, eMsgSubject)) jptr->subj = strdup(msg->cm_fields[eMsgSubject]);
+       if (!CM_IsEmpty(msg, emessageId)) jptr->msgn = strdup(msg->cm_fields[emessageId]);
        jptr->rfc822 = SmashStrBuf(&saved_rfc822_version);
 
        /* Add to the queue */
@@ -123,8 +123,10 @@ void JournalRunQueueMsg(struct jnlq *jmsg) {
 
        struct CtdlMessage *journal_msg = NULL;
        struct recptypes *journal_recps = NULL;
-       char *message_text = NULL;
+       StrBuf *message_text = NULL;
        char mime_boundary[256];
+       long mblen;
+       long rfc822len;
        char recipient[256];
        char inetemail[256];
        static int seq = 0;
@@ -150,14 +152,17 @@ void JournalRunQueueMsg(struct jnlq *jmsg) {
                        journal_msg->cm_magic = CTDLMESSAGE_MAGIC;
                        journal_msg->cm_anon_type = MES_NORMAL;
                        journal_msg->cm_format_type = FMT_RFC822;
-                       journal_msg->cm_fields['J'] = strdup("is journal");
-                       journal_msg->cm_fields['A'] = jmsg->from;
-                       journal_msg->cm_fields['N'] = jmsg->node;
-                       journal_msg->cm_fields['F'] = jmsg->rfca;
-                       journal_msg->cm_fields['U'] = jmsg->subj;
-
-                       sprintf(mime_boundary, "--Citadel-Journal-%08lx-%04x--", time(NULL), ++seq);
-                       message_text = malloc(strlen(jmsg->rfc822) + sizeof(struct recptypes) + 1024);
+                       CM_SetField(journal_msg, eJournal, HKEY("is journal"));
+                       CM_SetField(journal_msg, eAuthor, jmsg->from, strlen(jmsg->from));
+                       CM_SetField(journal_msg, eNodeName, jmsg->node, strlen(jmsg->node));
+                       CM_SetField(journal_msg, erFc822Addr, jmsg->rfca, strlen(jmsg->rfca));
+                       CM_SetField(journal_msg, eMsgSubject, jmsg->subj, strlen(jmsg->subj));
+
+                       mblen = snprintf(mime_boundary, sizeof(mime_boundary),
+                                        "--Citadel-Journal-%08lx-%04x--", time(NULL), ++seq);
+                       rfc822len = strlen(jmsg->rfc822);
+                      
+                       message_text = NewStrBufPlain(NULL, rfc822len + sizeof(struct recptypes) + 1024);
 
                        /*
                         * Here is where we begin to compose the journalized message.
@@ -165,45 +170,69 @@ void JournalRunQueueMsg(struct jnlq *jmsg) {
                         *       requested by a paying customer, and yes, it is intentionally
                         *       spelled wrong.  Do NOT remove or change it.
                         */
-                       sprintf(message_text,
-                               "Content-type: multipart/mixed; boundary=\"%s\"\r\n"
-                               "Content-Identifer: ExJournalReport\r\n"
-                               "MIME-Version: 1.0\r\n"
-                               "\n"
-                               "--%s\r\n"
-                               "Content-type: text/plain\r\n"
-                               "\r\n"
-                               "Sender: %s "
-                       ,
-                               mime_boundary,
-                               mime_boundary,
-                               ( journal_msg->cm_fields['A'] ? journal_msg->cm_fields['A'] : "(null)" )
-                       );
-
-                       if (journal_msg->cm_fields['F']) {
-                               sprintf(&message_text[strlen(message_text)], "<%s>",
-                                       journal_msg->cm_fields['F']);
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY("Content-type: multipart/mixed; boundary=\""), 0);
+
+                       StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
+
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY("\"\r\n"
+                                    "Content-Identifer: ExJournalReport\r\n"
+                                    "MIME-Version: 1.0\r\n"
+                                    "\n"
+                                    "--"), 0);
+
+                       StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
+
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY("\r\n"
+                                    "Content-type: text/plain\r\n"
+                                    "\r\n"
+                                    "Sender: "), 0);
+
+                       if (CM_IsEmpty(journal_msg, eAuthor))
+                               StrBufAppendBufPlain(
+                                       message_text, 
+                                       journal_msg->cm_fields[eAuthor], -1, 0);
+                       else
+                               StrBufAppendBufPlain(
+                                       message_text, 
+                                       HKEY("(null)"), 0);
+
+                       if (!CM_IsEmpty(journal_msg, erFc822Addr)) {
+                               StrBufAppendPrintf(message_text, " <%s>",
+                                                  journal_msg->cm_fields[erFc822Addr]);
                        }
-                       else if (journal_msg->cm_fields['N']) {
-                               sprintf(&message_text[strlen(message_text)], "@ %s",
-                                       journal_msg->cm_fields['N']);
+                       else if (!CM_IsEmpty(journal_msg, eNodeName)) {
+                               StrBufAppendPrintf(message_text, " @ %s",
+                                                  journal_msg->cm_fields[eNodeName]);
                        }
-
-                       sprintf(&message_text[strlen(message_text)],
-                               "\r\n"
-                               "Message-ID: <%s>\r\n"
-                               "Recipients:\r\n"
-                       ,
-                               jmsg->msgn
-                       );
+                       else
+                               StrBufAppendBufPlain(
+                                       message_text, 
+                                       HKEY(" "), 0);
+
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY("\r\n"
+                                    "Message-ID: <"), 0);
+
+                       StrBufAppendBufPlain(message_text, jmsg->msgn, -1, 0);
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY(">\r\n"
+                                    "Recipients:\r\n"), 0);
 
                        if (jmsg->recps.num_local > 0) {
                                for (i=0; i<jmsg->recps.num_local; ++i) {
                                        extract_token(recipient, jmsg->recps.recp_local,
                                                        i, '|', sizeof recipient);
                                        local_to_inetemail(inetemail, recipient, sizeof inetemail);
-                                       sprintf(&message_text[strlen(message_text)],
-                                               "       %s <%s>\r\n", recipient, inetemail);
+                                       StrBufAppendPrintf(message_text, 
+                                                          "    %s <%s>\r\n", recipient, inetemail);
                                }
                        }
 
@@ -211,8 +240,8 @@ void JournalRunQueueMsg(struct jnlq *jmsg) {
                                for (i=0; i<jmsg->recps.num_ignet; ++i) {
                                        extract_token(recipient, jmsg->recps.recp_ignet,
                                                        i, '|', sizeof recipient);
-                                       sprintf(&message_text[strlen(message_text)],
-                                               "       %s\r\n", recipient);
+                                       StrBufAppendPrintf(message_text, 
+                                                          "    %s\r\n", recipient);
                                }
                        }
 
@@ -220,31 +249,45 @@ void JournalRunQueueMsg(struct jnlq *jmsg) {
                                for (i=0; i<jmsg->recps.num_internet; ++i) {
                                        extract_token(recipient, jmsg->recps.recp_internet,
                                                        i, '|', sizeof recipient);
-                                       sprintf(&message_text[strlen(message_text)],
+                                       StrBufAppendPrintf(message_text, 
                                                "       %s\r\n", recipient);
                                }
                        }
 
-                       sprintf(&message_text[strlen(message_text)],
-                               "\r\n"
-                               "--%s\r\n"
-                               "Content-type: message/rfc822\r\n"
-                               "\r\n"
-                               "%s"
-                               "--%s--\r\n"
-                       ,
-                               mime_boundary,
-                               jmsg->rfc822,
-                               mime_boundary
-                       );
-
-                       journal_msg->cm_fields['M'] = message_text;
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY("\r\n"
+                                    "--"), 0);
+
+                       StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
+
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY("\r\n"
+                                    "Content-type: message/rfc822\r\n"
+                                    "\r\n"), 0);
+
+                       StrBufAppendBufPlain(message_text, jmsg->rfc822, rfc822len, 0);
+
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY("--"), 0);
+
+                       StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
+
+                       StrBufAppendBufPlain(
+                               message_text, 
+                               HKEY("--\r\n"), 0);
+
+                       CM_SetAsFieldSB(journal_msg, eMesageText, &message_text);
                        free(jmsg->rfc822);
                        free(jmsg->msgn);
+                       jmsg->rfc822 = NULL;
+                       jmsg->msgn = NULL;
                        
                        /* Submit journal message */
                        CtdlSubmitMsg(journal_msg, journal_recps, "", 0);
-                       CtdlFreeMessage(journal_msg);
+                       CM_Free(journal_msg);
                }
 
                free_recipients(journal_recps);
index f84020e7a12aa461ea0f4d917ee7d0670e80c902..00e190839bda557cdfeb6baafb410bf0f52e4245 100644 (file)
@@ -62,8 +62,8 @@ void hunt_for_autocomplete(long msgnum, char *search_string) {
        msg = CtdlFetchMessage(msgnum, 1);
        if (msg == NULL) return;
 
-       v = vcard_load(msg->cm_fields['M']);
-       CtdlFreeMessage(msg);
+       v = vcard_load(msg->cm_fields[eMesageText]);
+       CM_Free(msg);
 
        /*
         * Try to match from a friendly name (the "fn" field).  If there is
index fb95d613b4a1fc2a2df963a686a31f15d6bb15d0..891c2cccffe57429b8b54729edab3c49e5559bcb 100644 (file)
@@ -72,20 +72,18 @@ int blog_upload_beforesave(struct CtdlMessage *msg) {
        /* 
         * If the message doesn't have an EUID, give it one.
         */
-       if (msg->cm_fields['E'] == NULL)
+       if (CM_IsEmpty(msg, eExclusiveID))
        {
-               char uuid[BLOG_EUIDBUF_SIZE];
+               char uuid[SIZ];
                generate_uuid(uuid);
-               msg->cm_fields['E'] = strdup(uuid);
+               CM_SetField(msg, eExclusiveID, uuid, strlen(uuid));
        }
 
        /*
         * We also want to define a maximum length, whether we generated it or not.
         */
-       else if (strlen(msg->cm_fields['E']) >= BLOG_EUIDBUF_SIZE) {
-               msg->cm_fields['E'][BLOG_EUIDBUF_SIZE-1] = 0;
-       }
-
+       CM_CutFieldAt(msg, eExclusiveID, BLOG_EUIDBUF_SIZE - 1);
+       
        /* Now allow the save to complete. */
        return(0);
 }
index d9236bd33c74111f7a6b7c258e8f5dfbec8d7bfd..1acd28251aa688ad4b5fcb6e44fc1580e3ff000b 100644 (file)
@@ -30,6 +30,7 @@
 #include "msgbase.h"
 #include "internet_addressing.h"
 #include "serv_calendar.h"
+#include "room_ops.h"
 #include "euidindex.h"
 #include "ical_dezonify.h"
 
@@ -98,6 +99,7 @@ icalcomponent *ical_encapsulate_subcomponent(icalcomponent *subcomp) {
  */
 void ical_write_to_cal(struct ctdluser *u, icalcomponent *cal) {
        char *ser = NULL;
+       long serlen;
        icalcomponent *encaps = NULL;
        struct CtdlMessage *msg = NULL;
        icalcomponent *tmp=NULL;
@@ -119,13 +121,15 @@ void ical_write_to_cal(struct ctdluser *u, icalcomponent *cal) {
        ser = icalcomponent_as_ical_string_r(cal);
        if (ser == NULL) return;
 
+       serlen = strlen(ser);
+
        /* If the caller supplied a user, write to that user's default calendar room */
        if (u) {
                /* This handy API function does all the work for us. */
                CtdlWriteObject(USERCALENDARROOM,       /* which room */
                        "text/calendar",        /* MIME type */
                        ser,                    /* data */
-                       strlen(ser)+1,          /* length */
+                       serlen + 1,             /* length */
                        u,                      /* which user */
                        0,                      /* not binary */
                        0,                      /* don't delete others of this type */
@@ -135,22 +139,28 @@ void ical_write_to_cal(struct ctdluser *u, icalcomponent *cal) {
 
        /* If the caller did not supply a user, write to the currently selected room */
        if (!u) {
+               struct CitContext *CCC = CC;
+               StrBuf *MsgBody;
+
                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 = 4;
-               msg->cm_fields['A'] = strdup(CC->user.fullname);
-               msg->cm_fields['O'] = strdup(CC->room.QRname);
-               msg->cm_fields['N'] = strdup(config.c_nodename);
-               msg->cm_fields['H'] = strdup(config.c_humannode);
-               msg->cm_fields['M'] = malloc(strlen(ser) + 40);
-               strcpy(msg->cm_fields['M'], "Content-type: text/calendar\r\n\r\n");
-               strcat(msg->cm_fields['M'], ser);
+               CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
+               CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
+               CM_SetField(msg, eNodeName, config.c_nodename, strlen(config.c_nodename));
+               CM_SetField(msg, eHumanNode, config.c_humannode, strlen(config.c_humannode));
+
+               MsgBody = NewStrBufPlain(NULL, serlen + 100);
+               StrBufAppendBufPlain(MsgBody, HKEY("Content-type: text/calendar\r\n\r\n"), 0);
+               StrBufAppendBufPlain(MsgBody, ser, serlen, 0);
+
+               CM_SetAsFieldSB(msg, eMesageText, &MsgBody);
        
                /* Now write the data */
                CtdlSubmitMsg(msg, NULL, "", QP_EADDR);
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
        }
 
        /* In either case, now we can free the serialized calendar object */
@@ -183,7 +193,7 @@ void ical_send_a_reply(icalcomponent *request, char *action) {
        struct CtdlMessage *msg = NULL;
        struct recptypes *valid = NULL;
 
-       strcpy(organizer_string, "");
+       *organizer_string = '\0';
        strcpy(summary_string, "Calendar item");
 
        if (request == NULL) {
@@ -302,7 +312,7 @@ void ical_send_a_reply(icalcomponent *request, char *action) {
                if (msg != NULL) {
                        valid = validate_recipients(organizer_string, NULL, 0);
                        CtdlSubmitMsg(msg, valid, "", QP_EADDR);
-                       CtdlFreeMessage(msg);
+                       CM_Free(msg);
                        free_recipients(valid);
                }
        }
@@ -376,7 +386,7 @@ void ical_respond(long msgnum, char *partnum, char *action) {
 
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, partnum);
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_locate_part,              /* callback function */
                NULL, NULL,
@@ -387,7 +397,7 @@ void ical_respond(long msgnum, char *partnum, char *action) {
        /* We're done with the incoming message, because we now have a
         * calendar object in memory.
         */
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        /*
         * Here is the real meat of this function.  Handle the event.
@@ -632,14 +642,14 @@ int ical_update_my_calendar_with_reply(icalcomponent *cal) {
                return(2);                      /* internal error */
        }
        oec.c = NULL;
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_locate_original_event,    /* callback function */
                NULL, NULL,
                &oec,                           /* user data */
                0
        );
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        original_event = oec.c;
        if (original_event == NULL) {
@@ -679,7 +689,7 @@ int ical_update_my_calendar_with_reply(icalcomponent *cal) {
                if (msg != NULL) {
                        CIT_ICAL->avoid_sending_invitations = 1;
                        CtdlSubmitMsg(msg, NULL, roomname, QP_EADDR);
-                       CtdlFreeMessage(msg);
+                       CM_Free(msg);
                        CIT_ICAL->avoid_sending_invitations = 0;
                }
        }
@@ -719,7 +729,7 @@ void ical_handle_rsvp(long msgnum, char *partnum, char *action) {
 
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, partnum);
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_locate_part,              /* callback function */
                NULL, NULL,
@@ -730,7 +740,7 @@ void ical_handle_rsvp(long msgnum, char *partnum, char *action) {
        /* We're done with the incoming message, because we now have a
         * calendar object in memory.
         */
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        /*
         * Here is the real meat of this function.  Handle the event.
@@ -1151,14 +1161,14 @@ void ical_hunt_for_conflicts_backend(long msgnum, void *data) {
        if (msg == NULL) return;
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, "_HUNT_");
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_locate_part,              /* callback function */
                NULL, NULL,
                (void *) &ird,                  /* user data */
                0
        );
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        if (ird.cal == NULL) return;
 
@@ -1220,7 +1230,7 @@ void ical_conflicts(long msgnum, char *partnum) {
 
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, partnum);
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_locate_part,              /* callback function */
                NULL, NULL,
@@ -1228,7 +1238,7 @@ void ical_conflicts(long msgnum, char *partnum) {
                0
        );
 
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        if (ird.cal != NULL) {
                ical_hunt_for_conflicts(ird.cal);
@@ -1401,14 +1411,14 @@ void ical_freebusy_backend(long msgnum, void *data) {
        if (msg == NULL) return;
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, "_HUNT_");
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_locate_part,              /* callback function */
                NULL, NULL,
                (void *) &ird,                  /* user data */
                0
        );
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        if (ird.cal) {
                ical_add_to_freebusy(fb, ird.cal);              /* Add VEVENT times to VFREEBUSY */
@@ -1602,14 +1612,14 @@ void ical_getics_backend(long msgnum, void *data) {
        if (msg == NULL) return;
        memset(&ird, 0, sizeof ird);
        strcpy(ird.desired_partnum, "_HUNT_");
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_locate_part,              /* callback function */
                NULL, NULL,
                (void *) &ird,                  /* user data */
                0
        );
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        if (ird.cal == NULL) return;
 
@@ -2201,7 +2211,7 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal)
                if (msg != NULL) {
                        valid = validate_recipients(attendees_string, NULL, 0);
                        CtdlSubmitMsg(msg, valid, "", QP_EADDR);
-                       CtdlFreeMessage(msg);
+                       CM_Free(msg);
                        free_recipients(valid);
                }
        }
@@ -2285,10 +2295,10 @@ void ical_obj_beforesave_backend(char *name, char *filename, char *partnum,
                char *disp, void *content, char *cbtype, char *cbcharset, size_t length,
                char *encoding, char *cbid, void *cbuserdata)
 {
+       const char* pch;
        icalcomponent *cal, *nested_event, *nested_todo, *whole_cal;
        icalproperty *p;
        char new_uid[256] = "";
-       char buf[1024] = "";
        struct CtdlMessage *msg = (struct CtdlMessage *) cbuserdata;
 
        if (!msg) return;
@@ -2334,13 +2344,10 @@ void ical_obj_beforesave_backend(char *name, char *filename, char *partnum,
                                p = ical_ctdl_get_subprop(cal, ICAL_UID_PROPERTY);
                        }
                        if (p != NULL) {
-                               safestrncpy(buf, icalproperty_get_comment(p), sizeof buf);
-                               if (!IsEmptyStr(buf)) {
-                                       if (msg->cm_fields['E'] != NULL) {
-                                               free(msg->cm_fields['E']);
-                                       }
-                                       msg->cm_fields['E'] = strdup(buf);
-                                       syslog(LOG_DEBUG, "Saving calendar UID <%s>\n", buf);
+                               pch = icalproperty_get_comment(p);
+                               if (!IsEmptyStr(pch)) {
+                                       CM_SetField(msg, eExclusiveID, pch, strlen(pch));
+                                       syslog(LOG_DEBUG, "Saving calendar UID <%s>\n", pch);
                                }
                        }
 
@@ -2348,12 +2355,12 @@ void ical_obj_beforesave_backend(char *name, char *filename, char *partnum,
 
                        p = ical_ctdl_get_subprop(cal, ICAL_SUMMARY_PROPERTY);
                        if (p != NULL) {
-                               safestrncpy(buf, icalproperty_get_comment(p), sizeof buf);
-                               if (!IsEmptyStr(buf)) {
-                                       if (msg->cm_fields['U'] != NULL) {
-                                               free(msg->cm_fields['U']);
-                                       }
-                                       msg->cm_fields['U'] = rfc2047encode(buf, strlen(buf));
+                               pch = icalproperty_get_comment(p);
+                               if (!IsEmptyStr(pch)) {
+                                       char *subj;
+
+                                       subj = rfc2047encode(pch, strlen(pch));
+                                       CM_SetAsField(msg, eMsgSubject, &subj, strlen(subj));
                                }
                        }
 
@@ -2364,11 +2371,7 @@ void ical_obj_beforesave_backend(char *name, char *filename, char *partnum,
                                time_t idtstart;
                                idtstart = icaltime_as_timet(icalproperty_get_dtstart(p));
                                if (idtstart > 0) {
-                                       if (msg->cm_fields['T'] != NULL) {
-                                               free(msg->cm_fields['T']);
-                                       }
-                                       msg->cm_fields['T'] = strdup("000000000000000000");
-                                       sprintf(msg->cm_fields['T'], "%ld", idtstart);
+                                       CM_SetFieldLONG(msg, eTimestamp, idtstart);
                                }
                        }
 
@@ -2405,12 +2408,12 @@ int ical_obj_beforesave(struct CtdlMessage *msg)
                return(1);              /* You tried to save a non-RFC822 message! */
        }
 
-       if (msg->cm_fields['M'] == NULL) {
+       if (CM_IsEmpty(msg, eMesageText)) {
                return(1);              /* You tried to save a null message! */
        }
 
        /* Do all of our lovely back-end parsing */
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_obj_beforesave_backend,
                NULL, NULL,
@@ -2476,10 +2479,10 @@ int ical_obj_aftersave(struct CtdlMessage *msg)
        if (msg->cm_format_type != 4) return(1);
 
        /* Reject null messages */
-       if (msg->cm_fields['M'] == NULL) return(1);
+       if (CM_IsEmpty(msg, eMesageText)) return(1);
        
        /* Now recurse through it looking for our icalendar data */
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *ical_obj_aftersave_backend,
                NULL, NULL,
index c4b8a5d4fe05c2111f96e3bed48d8cc75bfbc736..ae24461aa028b491f8174dd6faea08d2fadcdbd5 100644 (file)
@@ -180,10 +180,7 @@ int clamd(struct CtdlMessage *msg) {
        }
 
        if (is_virus) {
-               if (msg->cm_fields['0'] != NULL) {
-                       free(msg->cm_fields['0']);
-               }
-               msg->cm_fields['0'] = strdup("message rejected by virus filter");
+               CM_SetField(msg, eErrorMsg, HKEY("message rejected by virus filter"));
        }
 
 bail:  close(sock);
index 86e8b30b0539b4b0b9c4dd3cc4a87f40884a3214..28a9a8d742804f510ced72809e1986581d768237 100644 (file)
@@ -168,8 +168,8 @@ void dspam_do_msg(long msgnum, void *userdata)
        {
 /* Copy to a safe place */
 
-               msg->cm_fields['G'] = malloc (CTX->signature->length * 2);
-               CtdlEncodeBase64(msg->cm_fields['G'], CTX->signature->data, CTX->signature->length, 0);
+               msg->cm_fields[eErrorMsg] = malloc (CTX->signature->length * 2);
+               CtdlEncodeBase64(msg->cm_fields[eErrorMsg], CTX->signature->data, CTX->signature->length, 0);
        }
        free(msgtext);
 
index 7da3ef84ebbd53726c494e6c11ce68cb48475279..583b86dd504019e844aa0ccbe9c5a906b246b976 100644 (file)
@@ -199,8 +199,8 @@ void GatherPurgeMessages(struct ctdlroom *qrbuf, void *data) {
 
                        msg = CtdlFetchMessage(delnum, 0); /* dont need body */
                        if (msg != NULL) {
-                               xtime = atol(msg->cm_fields['T']);
-                               CtdlFreeMessage(msg);
+                               xtime = atol(msg->cm_fields[eTimestamp]);
+                               CM_Free(msg);
                        } else {
                                xtime = 0L;
                        }
@@ -773,7 +773,7 @@ int PurgeEuidIndexTable(void) {
 
                msg = CtdlFetchMessage(msgnum, 0);
                if (msg != NULL) {
-                       CtdlFreeMessage(msg);   /* it still exists, so do nothing */
+                       CM_Free(msg);   /* it still exists, so do nothing */
                }
                else {
                        eptr = (struct EPurgeList *) malloc(sizeof(struct EPurgeList));
index a519548faee6271acc0b03252c6e7d1f82544115..ef253c8760455a6f52ec312a817b8807b7b1b955 100644 (file)
@@ -154,6 +154,7 @@ eNotifyType extNotify_getConfigMessage(char *username,
        int num_msgs = 0;
        int a;
        char *configMsg;
+       long clen;
        char *pch;
 
        // Get the user
@@ -185,14 +186,14 @@ eNotifyType extNotify_getConfigMessage(char *username,
        for (a = 0; a < num_msgs; ++a) {
                msg = CtdlFetchMessage(msglist[a], 1);
                if (msg != NULL) {
-                       if ((msg->cm_fields['U'] != NULL) &&
-                           (strncasecmp(msg->cm_fields['U'],
+                       if (!CM_IsEmpty(msg, eMsgSubject) &&
+                           (strncasecmp(msg->cm_fields[eMsgSubject],
                                         PAGER_CONFIG_MESSAGE,
                                         strlen(PAGER_CONFIG_MESSAGE)) == 0))
                        {
                                break;
                        }
-                       CtdlFreeMessage(msg);
+                       CM_Free(msg);
                        msg = NULL;
                }
        }
@@ -204,9 +205,8 @@ eNotifyType extNotify_getConfigMessage(char *username,
        // Do a simple string search to see if 'funambol' is selected as the
        // type. This string would be at the very top of the message contents.
 
-       configMsg = msg->cm_fields['M'];
-       msg->cm_fields['M'] = NULL;
-       CtdlFreeMessage(msg);
+       CM_GetAsField(msg, eMesageText, &configMsg, &clen);
+       CM_Free(msg);
 
        /* here we would find the pager number... */
        pch = strchr(configMsg, '\n');
@@ -280,14 +280,14 @@ void process_notify(long NotifyMsgnum, void *usrdata)
        Ctx = (NotifyContext*) usrdata;
 
        msg = CtdlFetchMessage(NotifyMsgnum, 1);
-       if ( msg->cm_fields['2'] != NULL)
+       if (!CM_IsEmpty(msg, eExtnotify))
        {
                Type = extNotify_getConfigMessage(
-                       msg->cm_fields['2'],
+                       msg->cm_fields[eExtnotify],
                        &PagerNo,
                        &FreeMe);
 
-               pch = strstr(msg->cm_fields['M'], "msgid|");
+               pch = strstr(msg->cm_fields[eMesageText], "msgid|");
                if (pch != NULL)
                        msgnum = atol(pch + sizeof("msgid"));
 
@@ -303,8 +303,8 @@ void process_notify(long NotifyMsgnum, void *usrdata)
                        notify_http_server(remoteurl,
                                           file_funambol_msg,
                                           strlen(file_funambol_msg),/*GNA*/
-                                          msg->cm_fields['2'],
-                                          msg->cm_fields['I'],
+                                          msg->cm_fields[eExtnotify],
+                                          msg->cm_fields[emessageId],
                                           msgnum,
                                           NULL);
                        break;
@@ -336,8 +336,8 @@ void process_notify(long NotifyMsgnum, void *usrdata)
                                notify_http_server(URLBuf,
                                                   ChrPtr(FileBuf),
                                                   StrLength(FileBuf),
-                                                  msg->cm_fields['2'],
-                                                  msg->cm_fields['I'],
+                                                  msg->cm_fields[eExtnotify],
+                                                  msg->cm_fields[emessageId],
                                                   msgnum,
                                                   NULL);
                        }
@@ -351,7 +351,7 @@ void process_notify(long NotifyMsgnum, void *usrdata)
 
                        commandSiz = sizeof(config.c_pager_program) +
                                strlen(PagerNo) +
-                               strlen(msg->cm_fields['2']) + 5;
+                               strlen(msg->cm_fields[eExtnotify]) + 5;
 
                        command = malloc(commandSiz);
 
@@ -360,7 +360,7 @@ void process_notify(long NotifyMsgnum, void *usrdata)
                                 "%s %s -u %s",
                                 config.c_pager_program,
                                 PagerNo,
-                                msg->cm_fields['2']);
+                                msg->cm_fields[eExtnotify]);
 
                        system(command);
                        free(command);
@@ -372,7 +372,7 @@ void process_notify(long NotifyMsgnum, void *usrdata)
        }
        if (FreeMe != NULL)
                free(FreeMe);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        todelete[0] = NotifyMsgnum;
        CtdlDeleteMessages(FNBL_QUEUE_ROOM, todelete, 1, "");
 }
index c7aab3468911b9e49c853e85a9008d21000dc243..20246c90d02a38ac25193743a01440340b5fca48 100644 (file)
@@ -36,6 +36,7 @@
 #include <curl/curl.h>
 
 #include "citadel.h"
+#include "citserver.h"
 #include "citadel_dirs.h"
 #include "clientsocket.h"
 #include "sysdep.h"
@@ -264,6 +265,7 @@ eNextState EvaluateResult(AsyncIO *IO)
                CtdlAideMessage(ChrPtr(ErrMsg),
                                "External notifier: "
                                "unable to contact notification host!");
+               FreeStrBuf(&ErrMsg);
        }
 
        syslog(LOG_DEBUG, "Funambol notified\n");
@@ -300,7 +302,7 @@ eNextState EvaluateResult(AsyncIO *IO)
        ///if (SOAPMessage != NULL) free(SOAPMessage);
        ///if (buf != NULL) free(buf);
        ///FreeStrBuf (&ReplyBuf);
-       return 0;
+       return eTerminateConnection;
 }
 
 eNextState ExtNotifyTerminateDB(AsyncIO *IO)
index 8e668778817a405208c55cc6ab3ffd7e34f217ad..6288bfc9ab99adb0a240c99b739aab54da32622e 100644 (file)
@@ -126,9 +126,9 @@ void ft_index_message(long msgnum, int op) {
                return;
        }
 
-       if (msg->cm_fields['1'] != NULL) {
+       if (!CM_IsEmpty(msg, eSuppressIdx)) {
                syslog(LOG_DEBUG, "ft_index_message() excluded msg %ld", msgnum);
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
                return;
        }
 
@@ -139,7 +139,7 @@ void ft_index_message(long msgnum, int op) {
         */
        CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
        CtdlOutputPreLoadedMsg(msg, MT_CITADEL, HEADERS_ALL, 0, 1, 0);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        msgtext = CC->redirect_buffer;
        CC->redirect_buffer = NULL;
        if (msgtext != NULL) {
index 396e6070c6808516cdee483925cec7f8bbad8589..ed7f271651c79a7c71dc1801c8747fbfc7fd6240 100644 (file)
@@ -110,8 +110,8 @@ void imap_fetch_internaldate(struct CtdlMessage *msg) {
        time_t msgdate;
 
        if (!msg) return;
-       if (msg->cm_fields['T'] != NULL) {
-               msgdate = atol(msg->cm_fields['T']);
+       if (!CM_IsEmpty(msg, eTimestamp)) {
+               msgdate = atol(msg->cm_fields[eTimestamp]);
        }
        else {
                msgdate = time(NULL);
@@ -355,12 +355,12 @@ void imap_output_envelope_from(struct CtdlMessage *msg) {
 
        /* For everything else, we do stuff. */
        IAPuts("(("); /* open double-parens */
-       plain_imap_strout(msg->cm_fields['A']); /* personal name */
+       plain_imap_strout(msg->cm_fields[eAuthor]);     /* personal name */
        IAPuts(" NIL ");        /* source route (not used) */
 
 
-       if (msg->cm_fields['F'] != NULL) {
-               process_rfc822_addr(msg->cm_fields['F'], user, node, name);
+       if (!CM_IsEmpty(msg, erFc822Addr)) {
+               process_rfc822_addr(msg->cm_fields[erFc822Addr], user, node, name);
                plain_imap_strout(user);                /* mailbox name (user id) */
                IAPuts(" ");
                if (!strcasecmp(node, config.c_nodename)) {
@@ -371,9 +371,9 @@ void imap_output_envelope_from(struct CtdlMessage *msg) {
                }
        }
        else {
-               plain_imap_strout(msg->cm_fields['A']); /* mailbox name (user id) */
+               plain_imap_strout(msg->cm_fields[eAuthor]); /* mailbox name (user id) */
                IAPuts(" ");
-               plain_imap_strout(msg->cm_fields['N']); /* host name */
+               plain_imap_strout(msg->cm_fields[eNodeName]);   /* host name */
        }
        
        IAPuts(")) "); /* close double-parens */
@@ -445,8 +445,8 @@ void imap_fetch_envelope(struct CtdlMessage *msg) {
        if (!msg) return;
 
        /* Parse the message date into an IMAP-format date string */
-       if (msg->cm_fields['T'] != NULL) {
-               msgdate = atol(msg->cm_fields['T']);
+       if (!CM_IsEmpty(msg, eTimestamp)) {
+               msgdate = atol(msg->cm_fields[eTimestamp]);
        }
        else {
                msgdate = time(NULL);
@@ -466,14 +466,14 @@ void imap_fetch_envelope(struct CtdlMessage *msg) {
        IAPuts(" ");
 
        /* Subject */
-       plain_imap_strout(msg->cm_fields['U']);
+       plain_imap_strout(msg->cm_fields[eMsgSubject]);
        IAPuts(" ");
 
        /* From */
        imap_output_envelope_from(msg);
 
        /* Sender (default to same as 'From' if not present) */
-       fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "Sender");
+       fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Sender");
        if (fieldptr != NULL) {
                imap_output_envelope_addr(fieldptr);
                free(fieldptr);
@@ -483,7 +483,7 @@ void imap_fetch_envelope(struct CtdlMessage *msg) {
        }
 
        /* Reply-to */
-       fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "Reply-to");
+       fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Reply-to");
        if (fieldptr != NULL) {
                imap_output_envelope_addr(fieldptr);
                free(fieldptr);
@@ -493,53 +493,53 @@ void imap_fetch_envelope(struct CtdlMessage *msg) {
        }
 
        /* To */
-       imap_output_envelope_addr(msg->cm_fields['R']);
+       imap_output_envelope_addr(msg->cm_fields[eRecipient]);
 
        /* Cc (we do it this way because there might be a legacy non-Citadel Cc: field present) */
-       fieldptr = msg->cm_fields['Y'];
+       fieldptr = msg->cm_fields[eCarbonCopY];
        if (fieldptr != NULL) {
                imap_output_envelope_addr(fieldptr);
        }
        else {
-               fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "Cc");
+               fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Cc");
                imap_output_envelope_addr(fieldptr);
                if (fieldptr != NULL) free(fieldptr);
        }
 
        /* Bcc */
-       fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "Bcc");
+       fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Bcc");
        imap_output_envelope_addr(fieldptr);
        if (fieldptr != NULL) free(fieldptr);
 
        /* In-reply-to */
-       fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "In-reply-to");
+       fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "In-reply-to");
        plain_imap_strout(fieldptr);
        IAPuts(" ");
        if (fieldptr != NULL) free(fieldptr);
 
        /* message ID */
-       len = strlen(msg->cm_fields['I']);
+       len = strlen(msg->cm_fields[emessageId]);
        
        if ((len == 0) || (
-                   (msg->cm_fields['I'][0] == '<') && 
-                   (msg->cm_fields['I'][len - 1] == '>'))
+                   (msg->cm_fields[emessageId][0] == '<') && 
+                   (msg->cm_fields[emessageId][len - 1] == '>'))
                )
        {
-               plain_imap_strout(msg->cm_fields['I']);
+               plain_imap_strout(msg->cm_fields[emessageId]);
        }
        else 
        {
                char *Buf = malloc(len + 3);
                long pos = 0;
                
-               if (msg->cm_fields['I'][0] != '<')
+               if (msg->cm_fields[emessageId][0] != '<')
                {
                        Buf[pos] = '<';
                        pos ++;
                }
-               memcpy(&Buf[pos], msg->cm_fields['I'], len);
+               memcpy(&Buf[pos], msg->cm_fields[emessageId], len);
                pos += len;
-               if (msg->cm_fields['I'][len] != '>')
+               if (msg->cm_fields[emessageId][len] != '>')
                {
                        Buf[pos] = '>';
                        pos++;
@@ -752,7 +752,7 @@ void imap_fetch_body(long msgnum, ConstStr item, int is_peek) {
         * (Note value of 1 passed as 'dont_decode' so client gets it encoded)
         */
        else {
-               mime_parser(msg->cm_fields['M'], NULL,
+               mime_parser(msg->cm_fields[eMesageText], NULL,
                            *imap_load_part, NULL, NULL,
                            section,
                            1
@@ -790,7 +790,7 @@ void imap_fetch_body(long msgnum, ConstStr item, int is_peek) {
        iaputs(&Imap->cached_body[pstart], pbytes);
 
        if (msg != NULL) {
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
        }
 
        /* Mark this message as "seen" *unless* this is a "peek" operation */
@@ -1019,7 +1019,7 @@ void imap_fetch_bodystructure (long msgnum, const char *item,
 
        /* For messages already stored in RFC822 format, we have to parse. */
        IAPuts("BODYSTRUCTURE ");
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                        NULL,
                        *imap_fetch_bodystructure_part, /* part */
                        *imap_fetch_bodystructure_pre,  /* pre-multi */
@@ -1084,7 +1084,7 @@ void imap_do_fetch_msg(int seq, citimap_command *Cmd) {
                 */
                else if (!strcasecmp(Cmd->Params[i].Key, "BODYSTRUCTURE")) {
                        if ((msg != NULL) && (!body_loaded)) {
-                               CtdlFreeMessage(msg);   /* need the whole thing */
+                               CM_Free(msg);   /* need the whole thing */
                                msg = NULL;
                        }
                        if (msg == NULL) {
@@ -1115,7 +1115,7 @@ void imap_do_fetch_msg(int seq, citimap_command *Cmd) {
        IAPuts(")\r\n");
        unbuffer_output();
        if (msg != NULL) {
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
        }
 }
 
index e7b3d69fe73a204bea2a2695410261c87c9fa40d..5485836a9666de4984d61fcc90905be3e732a3e9 100644 (file)
@@ -52,6 +52,7 @@
 #include "user_ops.h"
 #include "database.h"
 #include "msgbase.h"
+#include "room_ops.h"
 #include "internet_addressing.h"
 #include "serv_imap.h"
 #include "imap_tools.h"
@@ -371,7 +372,7 @@ void imap_append(int num_parms, ConstStr *Params) {
         * folder is selected, save its name so we can return there!!!!!)
         */
        if (Imap->selected) {
-               strcpy(savedroom, CC->room.QRname);
+               strcpy(savedroom, CCC->room.QRname);
        }
        CtdlUserGoto(roomname, 0, 0, &msgs, &new);
 
@@ -382,14 +383,12 @@ void imap_append(int num_parms, ConstStr *Params) {
         * For now, we allow "forgeries" if the room is one of the user's
         * private mailboxes.
         */
-       if (CC->logged_in) {
-          if ( ((CC->room.QRflags & QR_MAILBOX) == 0) && (config.c_imap_keep_from == 0)) {
-               if (msg->cm_fields['A'] != NULL) free(msg->cm_fields['A']);
-               if (msg->cm_fields['N'] != NULL) free(msg->cm_fields['N']);
-               if (msg->cm_fields['H'] != NULL) free(msg->cm_fields['H']);
-               msg->cm_fields['A'] = strdup(CC->user.fullname);
-               msg->cm_fields['N'] = strdup(config.c_nodename);
-               msg->cm_fields['H'] = strdup(config.c_humannode);
+       if (CCC->logged_in) {
+          if ( ((CCC->room.QRflags & QR_MAILBOX) == 0) && (config.c_imap_keep_from == 0)) {
+
+               CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
+               CM_SetField(msg, eNodeName, config.c_nodename, strlen(config.c_nodename));
+               CM_SetField(msg, eHumanNode, config.c_humannode, strlen(config.c_humannode));
            }
        }
 
@@ -429,7 +428,7 @@ void imap_append(int num_parms, ConstStr *Params) {
        }
 
        /* We don't need this buffer anymore */
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        if (new_message_flags != NULL) {
                imap_do_append_flags(new_msgnum, new_message_flags);
index 8cc3fd3d663f00311780d4c4377d297dc552e6ef..0697441d50bc9403ce21e7e2361ace491bee67aa 100644 (file)
@@ -125,7 +125,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "Bcc");
+                       fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Bcc");
                        if (fieldptr != NULL) {
                                if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
                                        match = 1;
@@ -142,9 +142,9 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (msg->cm_fields['T'] != NULL) {
+                       if (!CM_IsEmpty(msg, eTimestamp)) {
                                if (imap_datecmp(itemlist[pos+1].Key,
-                                               atol(msg->cm_fields['T'])) < 0) {
+                                               atol(msg->cm_fields[eTimestamp])) < 0) {
                                        match = 1;
                                }
                        }
@@ -168,7 +168,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                                need_to_free_msg = 1;
                        }
                        if (msg != NULL) {
-                               if (bmstrcasestr(msg->cm_fields['M'], itemlist[pos+1].Key)) {
+                               if (bmstrcasestr(msg->cm_fields[eMesageText], itemlist[pos+1].Key)) {
                                        match = 1;
                                }
                        }
@@ -183,14 +183,14 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       fieldptr = msg->cm_fields['Y'];
+                       fieldptr = msg->cm_fields[eCarbonCopY];
                        if (fieldptr != NULL) {
                                if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
                                        match = 1;
                                }
                        }
                        else {
-                               fieldptr = rfc822_fetch_field(msg->cm_fields['M'], "Cc");
+                               fieldptr = rfc822_fetch_field(msg->cm_fields[eMesageText], "Cc");
                                if (fieldptr != NULL) {
                                        if (bmstrcasestr(fieldptr, itemlist[pos+1].Key)) {
                                                match = 1;
@@ -229,10 +229,10 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (bmstrcasestr(msg->cm_fields['A'], itemlist[pos+1].Key)) {
+                       if (bmstrcasestr(msg->cm_fields[eAuthor], itemlist[pos+1].Key)) {
                                match = 1;
                        }
-                       if (bmstrcasestr(msg->cm_fields['F'], itemlist[pos+1].Key)) {
+                       if (bmstrcasestr(msg->cm_fields[erFc822Addr], itemlist[pos+1].Key)) {
                                match = 1;
                        }
                }
@@ -281,7 +281,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (strlen(msg->cm_fields['M']) > atoi(itemlist[pos+1].Key)) {
+                       if (strlen(msg->cm_fields[eMesageText]) > atoi(itemlist[pos+1].Key)) {
                                match = 1;
                        }
                }
@@ -308,9 +308,9 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (msg->cm_fields['T'] != NULL) {
+                       if (!CM_IsEmpty(msg, eTimestamp)) {
                                if (imap_datecmp(itemlist[pos+1].Key,
-                                               atol(msg->cm_fields['T'])) == 0) {
+                                               atol(msg->cm_fields[eTimestamp])) == 0) {
                                        match = 1;
                                }
                        }
@@ -338,9 +338,9 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (msg->cm_fields['T'] != NULL) {
+                       if (!CM_IsEmpty(msg, eTimestamp)) {
                                if (imap_datecmp(itemlist[pos+1].Key,
-                                               atol(msg->cm_fields['T'])) < 0) {
+                                               atol(msg->cm_fields[eTimestamp])) < 0) {
                                        match = 1;
                                }
                        }
@@ -354,9 +354,9 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (msg->cm_fields['T'] != NULL) {
+                       if (!CM_IsEmpty(msg, eTimestamp)) {
                                if (imap_datecmp(itemlist[pos+1].Key,
-                                               atol(msg->cm_fields['T'])) == 0) {
+                                               atol(msg->cm_fields[eTimestamp])) == 0) {
                                        match = 1;
                                }
                        }
@@ -370,9 +370,9 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (msg->cm_fields['T'] != NULL) {
+                       if (!CM_IsEmpty(msg, eTimestamp)) {
                                if (imap_datecmp(itemlist[pos+1].Key,
-                                               atol(msg->cm_fields['T'])) >= 0) {
+                                               atol(msg->cm_fields[eTimestamp])) >= 0) {
                                        match = 1;
                                }
                        }
@@ -386,9 +386,9 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (msg->cm_fields['T'] != NULL) {
+                       if (!CM_IsEmpty(msg, eTimestamp)) {
                                if (imap_datecmp(itemlist[pos+1].Key,
-                                               atol(msg->cm_fields['T'])) >= 0) {
+                                               atol(msg->cm_fields[eTimestamp])) >= 0) {
                                        match = 1;
                                }
                        }
@@ -402,7 +402,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (strlen(msg->cm_fields['M']) < atoi(itemlist[pos+1].Key)) {
+                       if (strlen(msg->cm_fields[eMesageText]) < atoi(itemlist[pos+1].Key)) {
                                match = 1;
                        }
                }
@@ -415,7 +415,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (bmstrcasestr(msg->cm_fields['U'], itemlist[pos+1].Key)) {
+                       if (bmstrcasestr(msg->cm_fields[eMsgSubject], itemlist[pos+1].Key)) {
                                match = 1;
                        }
                }
@@ -443,7 +443,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
                        need_to_free_msg = 1;
                }
                if (msg != NULL) {
-                       if (bmstrcasestr(msg->cm_fields['R'], itemlist[pos+1].Key)) {
+                       if (bmstrcasestr(msg->cm_fields[eRecipient], itemlist[pos+1].Key)) {
                                match = 1;
                        }
                }
@@ -531,7 +531,7 @@ int imap_do_search_msg(int seq, struct CtdlMessage *supplied_msg,
        }
 
        if (need_to_free_msg) {
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
        }
        return(match);
 }
index 5685e239225f39a05c5ec8a73cc2e18721e32619..8c4188bdbb93118c01f8b881662f4342ff3457f1 100644 (file)
@@ -53,6 +53,7 @@
 #include "config.h"
 #include "user_ops.h"
 #include "database.h"
+#include "room_ops.h"
 #include "msgbase.h"
 #include "internet_addressing.h"
 #include "serv_imap.h"
index e3be75c801641d6414c46d362524b1e856a49c63..7c0bedaa10aaf1cd89604a9c463b09f6c71b8e7f 100644 (file)
@@ -66,8 +66,8 @@ void inetcfg_setTo(struct CtdlMessage *msg) {
        char *conf;
        char buf[SIZ];
        
-       if (msg->cm_fields['M']==NULL) return;
-       conf = strdup(msg->cm_fields['M']);
+       if (CM_IsEmpty(msg, eMesageText)) return;
+       conf = strdup(msg->cm_fields[eMesageText]);
 
        if (conf != NULL) {
                do {
@@ -92,10 +92,10 @@ int inetcfg_aftersave(struct CtdlMessage *msg) {
        /* If this isn't the configuration room, or if this isn't a MIME
         * message, don't bother.
         */
-       if (strcasecmp(msg->cm_fields['O'], SYSCONFIGROOM)) return(0);
+       if (strcasecmp(msg->cm_fields[eOriginalRoom], SYSCONFIGROOM)) return(0);
        if (msg->cm_format_type != 4) return(0);
 
-       ptr = msg->cm_fields['M'];
+       ptr = msg->cm_fields[eMesageText];
        while (ptr != NULL) {
        
                linelen = strcspn(ptr, "\n");
@@ -122,7 +122,7 @@ void inetcfg_init_backend(long msgnum, void *userdata) {
                msg = CtdlFetchMessage(msgnum, 1);
                if (msg != NULL) {
                inetcfg_setTo(msg);
-                       CtdlFreeMessage(msg);
+                       CM_Free(msg);
        }
 }
 
index d84ce6244070503ba26030954d58b9410ab7ef37..72f3256dee2185293635ec91a9f0787982cca63d 100644 (file)
@@ -459,16 +459,17 @@ void flush_individual_conversation(struct imlog *im) {
        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_SetField(msg, eNodeName, NODENAME, strlen(NODENAME));
+       CM_SetAsFieldSB(msg, eMesageText, &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.
@@ -482,7 +483,7 @@ void flush_individual_conversation(struct imlog *im) {
        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) {
index 41a2fdf2497d3dc323e078292367069e235eaca0..d60da3e1eb0c182c2ef44f9152c403950bc4094a 100644 (file)
@@ -297,8 +297,8 @@ void migr_export_message(long msgnum) {
        client_write("<msg_meta_content_type>", 23); xml_strout(smi.meta_content_type); client_write("</msg_meta_content_type>\n", 25);
 
        client_write("<msg_text>", 10);
-       serialize_message(&smr, msg);
-       CtdlFreeMessage(msg);
+       CtdlSerializeMessage(&smr, msg);
+       CM_Free(msg);
 
        /* Predict the buffer size we need.  Expand the buffer if necessary. */
        int encoded_len = smr.len * 15 / 10 ;
index d04a49f1fdc6201657df4391a3dfc6479d55979c..8496c5c5acaafb0ba0563432aa71dcb0d28e2808 100644 (file)
@@ -55,7 +55,7 @@ void InspectQueuedRoom(SpoolControl **pSC,
 
 int HaveSpoolConfig(OneRoomNetCfg* RNCfg);
 
-
+void Netmap_AddMe(struct CtdlMessage *msg, const char *defl, long defllen);
 void network_do_spoolin(HashList *working_ignetcfg, HashList *the_netmap, int *netmap_changed);
 void network_consolidate_spoolout(HashList *working_ignetcfg, HashList *the_netmap);
 void free_spoolcontrol_struct(SpoolControl **scc);
index 1473385ae7eba7efe8b2af4fee4b69837b684c58..588cced6ad6cea299220ae3dac6090af244afbd6 100644 (file)
@@ -149,29 +149,29 @@ int filter_the_idiots(struct CtdlMessage *msg, char *target_room) {
                zap_room = 0;
                zap_node = 0;
 
-               if (msg->cm_fields['A'] != NULL) {
-                       if ( (!strcasecmp(msg->cm_fields['A'], fptr->fl_user))
+               if (!CM_IsEmpty(msg, eAuthor)) {
+                       if ( (!strcasecmp(msg->cm_fields[eAuthor], fptr->fl_user))
                           || (fptr->fl_user[0] == 0) ) {
                                zap_user = 1;
                        }
                }
 
-               if (msg->cm_fields['C'] != NULL) {
-                       if ( (!strcasecmp(msg->cm_fields['C'], fptr->fl_room))
+               if (!CM_IsEmpty(msg, eRemoteRoom)) {
+                       if ( (!strcasecmp(msg->cm_fields[eRemoteRoom], fptr->fl_room))
                           || (fptr->fl_room[0] == 0) ) {
                                zap_room = 1;
                        }
                }
 
-               if (msg->cm_fields['O'] != NULL) {
-                       if ( (!strcasecmp(msg->cm_fields['O'], fptr->fl_room))
+               if (!CM_IsEmpty(msg, eOriginalRoom)) {
+                       if ( (!strcasecmp(msg->cm_fields[eOriginalRoom], fptr->fl_room))
                           || (fptr->fl_room[0] == 0) ) {
                                zap_room = 1;
                        }
                }
 
-               if (msg->cm_fields['N'] != NULL) {
-                       if ( (!strcasecmp(msg->cm_fields['N'], fptr->fl_node))
+               if (!CM_IsEmpty(msg, eNodeName)) {
+                       if ( (!strcasecmp(msg->cm_fields[eNodeName], fptr->fl_node))
                           || (fptr->fl_node[0] == 0) ) {
                                zap_node = 1;
                        }
index b84c5dea2c941224fb7e31557495047521a54b6f..d44be90745cb17882c9727825379b75c67931440 100644 (file)
@@ -133,12 +133,12 @@ static void ListCalculateSubject(struct CtdlMessage *msg)
        int rlen;
        char *pCh;
 
-       if (msg->cm_fields['U'] == NULL) {
+       if (CM_IsEmpty(msg, eMsgSubject)) {
                Subject = NewStrBufPlain(HKEY("(no subject)"));
        }
        else {
                Subject = NewStrBufPlain(
-                       msg->cm_fields['U'], -1);
+                       msg->cm_fields[eMsgSubject], -1);
        }
        FlatSubject = NewStrBufPlain(NULL, StrLength(Subject));
        StrBuf_RFC822_to_Utf8(FlatSubject, Subject, NULL, NULL);
@@ -165,9 +165,7 @@ static void ListCalculateSubject(struct CtdlMessage *msg)
                StrBufRFC2047encode(&Subject, FlatSubject);
        }
 
-       if (msg->cm_fields['U'] != NULL)
-               free (msg->cm_fields['U']);
-       msg->cm_fields['U'] = SmashStrBuf(&Subject);
+       CM_SetAsFieldSB(msg, eMsgSubject, &Subject);
 
        FreeStrBuf(&FlatSubject);
 }
@@ -177,7 +175,10 @@ static void ListCalculateSubject(struct CtdlMessage *msg)
  */
 void network_deliver_digest(SpoolControl *sc)
 {
+       struct CitContext *CCC = CC;
+       long len;
        char buf[SIZ];
+       char *pbuf;
        struct CtdlMessage *msg = NULL;
        long msglen;
        struct recptypes *valid;
@@ -198,17 +199,16 @@ void network_deliver_digest(SpoolControl *sc)
        msg->cm_format_type = FMT_RFC822;
        msg->cm_anon_type = MES_NORMAL;
 
-       sprintf(buf, "%ld", time(NULL));
-       msg->cm_fields['T'] = strdup(buf);
-       msg->cm_fields['A'] = strdup(CC->room.QRname);
-       snprintf(buf, sizeof buf, "[%s]", CC->room.QRname);
-       msg->cm_fields['U'] = strdup(buf);
+       CM_SetFieldLONG(msg, eTimestamp, time(NULL));
+       CM_SetField(msg, eAuthor, CCC->room.QRname, strlen(CCC->room.QRname));
+       len = snprintf(buf, sizeof buf, "[%s]", CCC->room.QRname);
+       CM_SetField(msg, eMsgSubject, buf, len);
 
-       CtdlMsgSetCM_Fields(msg, 'F', SKEY(sc->Users[roommailalias]));
-       CtdlMsgSetCM_Fields(msg, 'R', SKEY(sc->Users[roommailalias]));
+       CM_SetField(msg, erFc822Addr, SKEY(sc->Users[roommailalias]));
+       CM_SetField(msg, eRecipient, SKEY(sc->Users[roommailalias]));
 
        /* Set the 'List-ID' header */
-       CtdlMsgSetCM_Fields(msg, 'L', SKEY(sc->ListID));
+       CM_SetField(msg, eListID, SKEY(sc->ListID));
 
        /*
         * Go fetch the contents of the digest
@@ -216,11 +216,11 @@ void network_deliver_digest(SpoolControl *sc)
        fseek(sc->digestfp, 0L, SEEK_END);
        msglen = ftell(sc->digestfp);
 
-       msg->cm_fields['M'] = malloc(msglen + 1);
+       pbuf = malloc(msglen + 1);
        fseek(sc->digestfp, 0L, SEEK_SET);
-       fread(msg->cm_fields['M'], (size_t)msglen, 1, sc->digestfp);
-       msg->cm_fields['M'][msglen] = '\0';
-
+       fread(pbuf, (size_t)msglen, 1, sc->digestfp);
+       pbuf[msglen] = '\0';
+       CM_SetAsField(msg, eMesageText, &pbuf, msglen);
        fclose(sc->digestfp);
        sc->digestfp = NULL;
 
@@ -239,7 +239,7 @@ void network_deliver_digest(SpoolControl *sc)
                valid->envelope_from = strdup(bounce_to);
                CtdlSubmitMsg(msg, valid, NULL, 0);
        }
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        free_recipients(valid);
 }
 
@@ -256,33 +256,33 @@ void network_process_digest(SpoolControl *sc, struct CtdlMessage *omsg, long *de
            (sc->digestfp == NULL))
                return;
 
-       msg = CtdlDuplicateMessage(omsg);
+       msg = CM_Duplicate(omsg);
        if (msg != NULL) {
                fprintf(sc->digestfp,
                        " -----------------------------------"
                        "------------------------------------"
                        "-------\n");
                fprintf(sc->digestfp, "From: ");
-               if (msg->cm_fields['A'] != NULL) {
+               if (!CM_IsEmpty(msg, eAuthor)) {
                        fprintf(sc->digestfp,
                                "%s ",
-                               msg->cm_fields['A']);
+                               msg->cm_fields[eAuthor]);
                }
-               if (msg->cm_fields['F'] != NULL) {
+               if (!CM_IsEmpty(msg, erFc822Addr)) {
                        fprintf(sc->digestfp,
                                "<%s> ",
-                               msg->cm_fields['F']);
+                               msg->cm_fields[erFc822Addr]);
                }
-               else if (msg->cm_fields['N'] != NULL) {
+               else if (!CM_IsEmpty(msg, eNodeName)) {
                        fprintf(sc->digestfp,
                                "@%s ",
-                               msg->cm_fields['N']);
+                               msg->cm_fields[eNodeName]);
                }
                fprintf(sc->digestfp, "\n");
-               if (msg->cm_fields['U'] != NULL) {
+               if (!CM_IsEmpty(msg, eMsgSubject)) {
                        fprintf(sc->digestfp,
                                "Subject: %s\n",
-                               msg->cm_fields['U']);
+                               msg->cm_fields[eMsgSubject]);
                }
 
                CC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
@@ -304,7 +304,7 @@ void network_process_digest(SpoolControl *sc, struct CtdlMessage *omsg, long *de
                FreeStrBuf(&CC->redirect_buffer);
 
                sc->num_msgs_spooled += 1;
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
        }
 }
 
@@ -324,23 +324,22 @@ void network_process_list(SpoolControl *sc, struct CtdlMessage *omsg, long *dele
         * in order to insert the [list name] in it, etc.
         */
 
-       msg = CtdlDuplicateMessage(omsg);
+       msg = CM_Duplicate(omsg);
 
 
-       CtdlMsgSetCM_Fields(msg, 'K', SKEY(sc->Users[roommailalias]));
+       CM_SetField(msg, eListID, SKEY(sc->Users[roommailalias]));
 
        /* if there is no other recipient, Set the recipient
         * of the list message to the email address of the
         * room itself.
         */
-       if ((msg->cm_fields['R'] == NULL) ||
-           IsEmptyStr(msg->cm_fields['R']))
+       if (CM_IsEmpty(msg, eRecipient))
        {
-               CtdlMsgSetCM_Fields(msg, 'R', SKEY(sc->Users[roommailalias]));
+               CM_SetField(msg, eRecipient, SKEY(sc->Users[roommailalias]));
        }
 
        /* Set the 'List-ID' header */
-       CtdlMsgSetCM_Fields(msg, 'L', SKEY(sc->ListID));
+       CM_SetField(msg, eListID, SKEY(sc->ListID));
 
 
        /* Prepend "[List name]" to the subject */
@@ -348,7 +347,7 @@ void network_process_list(SpoolControl *sc, struct CtdlMessage *omsg, long *dele
 
        /* Handle delivery */
        network_deliver_list(msg, sc, CC->room.QRname);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 /*
@@ -378,7 +377,7 @@ void network_deliver_list(struct CtdlMessage *msg, SpoolControl *sc, const char
                CtdlSubmitMsg(msg, valid, NULL, 0);
                free_recipients(valid);
        }
-       /* Do not call CtdlFreeMessage(msg) here; the caller will free it. */
+       /* Do not call CM_Free(msg) here; the caller will free it. */
 }
 
 
@@ -395,7 +394,7 @@ void network_process_participate(SpoolControl *sc, struct CtdlMessage *omsg, lon
        if (sc->Users[participate] == NULL)
                return;
 
-       msg = CtdlDuplicateMessage(omsg);
+       msg = CM_Duplicate(omsg);
 
        /* Only send messages which originated on our own
         * Citadel network, otherwise we'll end up sending the
@@ -403,13 +402,13 @@ void network_process_participate(SpoolControl *sc, struct CtdlMessage *omsg, lon
         * is rude...
         */
        ok_to_participate = 0;
-       if (msg->cm_fields['N'] != NULL) {
-               if (!strcasecmp(msg->cm_fields['N'],
+       if (!CM_IsEmpty(msg, eNodeName)) {
+               if (!strcasecmp(msg->cm_fields[eNodeName],
                                config.c_nodename)) {
                        ok_to_participate = 1;
                }
                
-               Buf = NewStrBufPlain(msg->cm_fields['N'], -1);
+               Buf = NewStrBufPlain(msg->cm_fields[eNodeName], -1);
                if (CtdlIsValidNode(NULL,
                                    NULL,
                                    Buf,
@@ -426,16 +425,16 @@ void network_process_participate(SpoolControl *sc, struct CtdlMessage *omsg, lon
                 * room itself, so the remote listserv doesn't
                 * reject us.
                 */
-               CtdlMsgSetCM_Fields(msg, 'F', SKEY(sc->Users[roommailalias]));
+               CM_SetField(msg, erFc822Addr, SKEY(sc->Users[roommailalias]));
 
                valid = validate_recipients(ChrPtr(sc->Users[participate]) , NULL, 0);
 
-               CtdlMsgSetCM_Fields(msg, 'R', SKEY(sc->Users[roommailalias]));
+               CM_SetField(msg, eRecipient, SKEY(sc->Users[roommailalias]));
                CtdlSubmitMsg(msg, valid, "", 0);
                free_recipients(valid);
        }
        FreeStrBuf(&Buf);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 void network_process_ignetpush(SpoolControl *sc, struct CtdlMessage *omsg, long *delete_after_send)
@@ -449,8 +448,6 @@ void network_process_ignetpush(SpoolControl *sc, struct CtdlMessage *omsg, long
        char buf[SIZ];
        char filename[PATH_MAX];
        FILE *fp;
-       size_t newpath_len;
-       char *newpath = NULL;
        StrBuf *Buf = NULL;
        int i;
        int bang = 0;
@@ -462,29 +459,19 @@ void network_process_ignetpush(SpoolControl *sc, struct CtdlMessage *omsg, long
        /*
         * Process IGnet push shares
         */
-       msg = CtdlDuplicateMessage(omsg);
+       msg = CM_Duplicate(omsg);
 
        /* Prepend our node name to the Path field whenever
         * sending a message to another IGnet node
         */
-       if (msg->cm_fields['P'] == NULL)
-       {
-               msg->cm_fields['P'] = strdup("username");
-       }
-       newpath_len = strlen(msg->cm_fields['P']) +
-               strlen(config.c_nodename) + 2;
-       newpath = malloc(newpath_len);
-       snprintf(newpath, newpath_len, "%s!%s",
-                config.c_nodename, msg->cm_fields['P']);
-       free(msg->cm_fields['P']);
-       msg->cm_fields['P'] = newpath;
-       
+       Netmap_AddMe(msg, HKEY("username"));
+
        /*
         * Determine if this message is set to be deleted
         * after sending out on the network
         */
-       if (msg->cm_fields['S'] != NULL) {
-               if (!strcasecmp(msg->cm_fields['S'], "CANCEL")) {
+       if (!CM_IsEmpty(msg, eSpecialField)) {
+               if (!strcasecmp(msg->cm_fields[eSpecialField], "CANCEL")) {
                        *delete_after_send = 1;
                }
        }
@@ -514,12 +501,12 @@ void network_process_ignetpush(SpoolControl *sc, struct CtdlMessage *omsg, long
                }
                
                /* Check for split horizon */
-               QN_syslog(LOG_DEBUG, "Path is %s\n", msg->cm_fields['P']);
-               bang = num_tokens(msg->cm_fields['P'], '!');
+               QN_syslog(LOG_DEBUG, "Path is %s\n", msg->cm_fields[eMessagePath]);
+               bang = num_tokens(msg->cm_fields[eMessagePath], '!');
                if (bang > 1) {
                        for (i=0; i<(bang-1); ++i) {
                                extract_token(buf,
-                                             msg->cm_fields['P'],
+                                             msg->cm_fields[eMessagePath],
                                              i, '!',
                                              sizeof buf);
 
@@ -545,20 +532,15 @@ void network_process_ignetpush(SpoolControl *sc, struct CtdlMessage *omsg, long
                         * room on the far end by setting the C field
                         * correctly
                         */
-                       if (msg->cm_fields['C'] != NULL) {
-                               free(msg->cm_fields['C']);
-                       }
                        if (StrLength(RemoteRoom) > 0) {
-                               msg->cm_fields['C'] =
-                                       strdup(ChrPtr(RemoteRoom));
+                               CM_SetField(msg, eRemoteRoom, SKEY(RemoteRoom));
                        }
                        else {
-                               msg->cm_fields['C'] =
-                                       strdup(CC->room.QRname);
+                               CM_SetField(msg, eRemoteRoom, CCC->room.QRname, strlen(CCC->room.QRname));
                        }
                        
                        /* serialize it for transmission */
-                       serialize_message(&sermsg, msg);
+                       CtdlSerializeMessage(&sermsg, msg);
                        if (sermsg.len > 0) {
                                
                                /* write it to a spool file */
@@ -596,7 +578,7 @@ void network_process_ignetpush(SpoolControl *sc, struct CtdlMessage *omsg, long
        FreeStrBuf(&Buf);
        FreeStrBuf(&Recipient);
        FreeStrBuf(&RemoteRoom);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
@@ -627,7 +609,7 @@ void network_spool_msg(long msgnum,
        network_process_participate(sc, msg, &delete_after_send);
        network_process_ignetpush(sc, msg, &delete_after_send);
        
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        /* update lastsent */
        sc->lastsent = msgnum;
index 02dbcabb23f3f7664b95a45f63ca001daf57a1fe..be4da12af30317f19d422a5f1ee6f37edb809bcb 100644 (file)
@@ -160,7 +160,23 @@ int HaveSpoolConfig(OneRoomNetCfg* RNCfg)
        return interested;
 }
 
+void Netmap_AddMe(struct CtdlMessage *msg, const char *defl, long defllen)
+{
+       long node_len;
+       char buf[SIZ];
 
+       /* prepend our node to the path */
+       if (CM_IsEmpty(msg, eMessagePath)) {
+               CM_SetField(msg, eMessagePath, defl, defllen);
+       }
+       node_len = strlen(config.c_nodename);
+       if (node_len >= SIZ) 
+               node_len = SIZ - 1;
+       memcpy(buf, config.c_nodename, node_len);
+       buf[node_len] = '!';
+       buf[node_len + 1] = '\0';
+       CM_PrependToField(msg, eMessagePath, buf, node_len + 1);
+}
 
 void InspectQueuedRoom(SpoolControl **pSC,
                       RoomProcList *room_to_spool,     
@@ -408,7 +424,6 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg,
        struct recptypes *recp = NULL;
        char target_room[ROOMNAMELEN];
        struct ser_ret sermsg;
-       char *oldpath = NULL;
        char filename[PATH_MAX];
        FILE *fp;
        const StrBuf *nexthop = NULL;
@@ -439,39 +454,26 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg,
        for (pos = 3; pos < size; ++pos) {
                field = buffer[pos];
                len = strlen(buffer + pos + 1);
-               msg->cm_fields[field] = malloc(len + 1);
-               memcpy (msg->cm_fields[field], buffer+ pos + 1, len + 1);
+               CM_SetField(msg, field, buffer + pos + 1, len);
                pos = pos + len + 1;
        }
 
        /* Check for message routing */
-       if (msg->cm_fields['D'] != NULL) {
-               if (strcasecmp(msg->cm_fields['D'], config.c_nodename)) {
+       if (!CM_IsEmpty(msg, eDestination)) {
+               if (strcasecmp(msg->cm_fields[eDestination], config.c_nodename)) {
 
                        /* route the message */
-                       Buf = NewStrBufPlain(msg->cm_fields['D'], -1);
+                       Buf = NewStrBufPlain(msg->cm_fields[eDestination], -1);
                        if (CtdlIsValidNode(&nexthop, 
                                            NULL, 
                                            Buf, 
                                            working_ignetcfg, 
                                            the_netmap) == 0) 
                        {
-                               /* prepend our node to the path */
-                               if (msg->cm_fields['P'] != NULL) {
-                                       oldpath = msg->cm_fields['P'];
-                                       msg->cm_fields['P'] = NULL;
-                               }
-                               else {
-                                       oldpath = strdup("unknown_user");
-                               }
-                               size = strlen(oldpath) + SIZ;
-                               msg->cm_fields['P'] = malloc(size);
-                               snprintf(msg->cm_fields['P'], size, "%s!%s",
-                                       config.c_nodename, oldpath);
-                               free(oldpath);
+                               Netmap_AddMe(msg, HKEY("unknown_user"));
 
                                /* serialize the message */
-                               serialize_message(&sermsg, msg);
+                               CtdlSerializeMessage(&sermsg, msg);
 
                                /* now send it */
                                if (StrLength(nexthop) == 0) {
@@ -495,7 +497,7 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg,
                                        QN_syslog(LOG_ERR, "%s: %s\n", filename, strerror(errno));
                                }
                                free(sermsg.ser);
-                               CtdlFreeMessage(msg);
+                               CM_Free(msg);
                                FreeStrBuf(&Buf);
                                return;
                        }
@@ -520,14 +522,14 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg,
         * connected that it's inevitable.)
         */
        if (network_usetable(msg) != 0) {
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
                return;
        }
 
        /* Learn network topology from the path */
-       if ((msg->cm_fields['N'] != NULL) && (msg->cm_fields['P'] != NULL)) {
-               NetworkLearnTopology(msg->cm_fields['N'], 
-                                    msg->cm_fields['P'], 
+       if (!CM_IsEmpty(msg, eNodeName) && !CM_IsEmpty(msg, eMessagePath)) {
+               NetworkLearnTopology(msg->cm_fields[eNodeName], 
+                                    msg->cm_fields[eMessagePath], 
                                     the_netmap, 
                                     netmap_changed);
        }
@@ -535,13 +537,13 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg,
        /* Is the sending node giving us a very persuasive suggestion about
         * which room this message should be saved in?  If so, go with that.
         */
-       if (msg->cm_fields['C'] != NULL) {
-               safestrncpy(target_room, msg->cm_fields['C'], sizeof target_room);
+       if (!CM_IsEmpty(msg, eRemoteRoom)) {
+               safestrncpy(target_room, msg->cm_fields[eRemoteRoom], sizeof target_room);
        }
 
        /* Otherwise, does it have a recipient?  If so, validate it... */
-       else if (msg->cm_fields['R'] != NULL) {
-               recp = validate_recipients(msg->cm_fields['R'], NULL, 0);
+       else if (!CM_IsEmpty(msg, eRecipient)) {
+               recp = validate_recipients(msg->cm_fields[eRecipient], NULL, 0);
                if (recp != NULL) if (recp->num_error != 0) {
                        network_bounce(msg,
                                "A message you sent could not be delivered due to an invalid address.\n"
@@ -555,28 +557,22 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg,
        }
 
        /* Our last shot at finding a home for this message is to see if
-        * it has the O field (Originating room) set.
+        * it has the eOriginalRoom (O) field (Originating room) set.
         */
-       else if (msg->cm_fields['O'] != NULL) {
-               safestrncpy(target_room, msg->cm_fields['O'], sizeof target_room);
+       else if (!CM_IsEmpty(msg, eOriginalRoom)) {
+               safestrncpy(target_room, msg->cm_fields[eOriginalRoom], sizeof target_room);
        }
 
        /* Strip out fields that are only relevant during transit */
-       if (msg->cm_fields['D'] != NULL) {
-               free(msg->cm_fields['D']);
-               msg->cm_fields['D'] = NULL;
-       }
-       if (msg->cm_fields['C'] != NULL) {
-               free(msg->cm_fields['C']);
-               msg->cm_fields['C'] = NULL;
-       }
+       CM_FlushField(msg, eDestination);
+       CM_FlushField(msg, eRemoteRoom);
 
        /* save the message into a room */
        if (PerformNetprocHooks(msg, target_room) == 0) {
                msg->cm_flags = CM_SKIP_HOOKS;
                CtdlSubmitMsg(msg, recp, target_room, 0);
        }
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        free_recipients(recp);
 }
 
index 95d5b51e7021f1202d06519b754f805e2bd7aeb3..c0baa5f9a342f33955936dbd55bf831016262a0f 100644 (file)
@@ -111,17 +111,17 @@ int network_usetable(struct CtdlMessage *msg)
        time_t now;
 
        /* Bail out if we can't generate a message ID */
-       if ((msg == NULL) || (msg->cm_fields['I'] == NULL) || (IsEmptyStr(msg->cm_fields['I'])))
+       if ((msg == NULL) || CM_IsEmpty(msg, emessageId))
        {
                return(0);
        }
 
        /* Generate the message ID */
-       msgid = NewStrBufPlain(msg->cm_fields['I'], -1);
+       msgid = NewStrBufPlain(msg->cm_fields[emessageId], -1);
        if (haschar(ChrPtr(msgid), '@') == 0) {
                StrBufAppendBufPlain(msgid, HKEY("@"), 0);
-               if (msg->cm_fields['N'] != NULL) {
-                       StrBufAppendBufPlain(msgid, msg->cm_fields['N'], -1, 0);
+               if (!CM_IsEmpty(msg, eNodeName)) {
+                       StrBufAppendBufPlain(msgid, msg->cm_fields[eNodeName], -1, 0);
                }
                else {
                        FreeStrBuf(&msgid);
@@ -348,14 +348,13 @@ void destroy_network_queue_room_locked (void)
 void network_bounce(struct CtdlMessage *msg, char *reason)
 {
        struct CitContext *CCC = CC;
-       char *oldpath = NULL;
        char buf[SIZ];
        char bouncesource[SIZ];
        char recipient[SIZ];
        struct recptypes *valid = NULL;
        char force_room[ROOMNAMELEN];
        static int serialnum = 0;
-       size_t size;
+       long len;
 
        QNM_syslog(LOG_DEBUG, "entering network_bounce()\n");
 
@@ -366,67 +365,37 @@ void network_bounce(struct CtdlMessage *msg, char *reason)
        /* 
         * Give it a fresh message ID
         */
-       if (msg->cm_fields['I'] != NULL) {
-               free(msg->cm_fields['I']);
-       }
-       snprintf(buf, sizeof buf, "%ld.%04lx.%04x@%s",
-               (long)time(NULL), (long)getpid(), ++serialnum, config.c_fqdn);
-       msg->cm_fields['I'] = strdup(buf);
+       len = snprintf(buf, sizeof(buf),
+                      "%ld.%04lx.%04x@%s",
+                      (long)time(NULL),
+                      (long)getpid(),
+                      ++serialnum,
+                      config.c_fqdn);
+
+       CM_SetField(msg, emessageId, buf, len);
 
        /*
         * FIXME ... right now we're just sending a bounce; we really want to
         * include the text of the bounced message.
         */
-       if (msg->cm_fields['M'] != NULL) {
-               free(msg->cm_fields['M']);
-       }
-       msg->cm_fields['M'] = strdup(reason);
+       CM_SetField(msg, eMesageText, reason, strlen(reason));
        msg->cm_format_type = 0;
 
        /*
         * Turn the message around
         */
-       if (msg->cm_fields['R'] == NULL) {
-               free(msg->cm_fields['R']);
-               msg->cm_fields['R'] = NULL;
-       }
-
-       if (msg->cm_fields['D'] == NULL) {
-               free(msg->cm_fields['D']);
-               msg->cm_fields['D'] = NULL;
-       }
-
-       snprintf(recipient, sizeof recipient, "%s@%s",
-               msg->cm_fields['A'], msg->cm_fields['N']);
+       CM_FlushField(msg, eRecipient);
+       CM_FlushField(msg, eDestination);
 
-       if (msg->cm_fields['A'] == NULL) {
-               free(msg->cm_fields['A']);
-       }
-
-       if (msg->cm_fields['N'] == NULL) {
-               free(msg->cm_fields['N']);
-       }
-
-       if (msg->cm_fields['U'] == NULL) {
-               free(msg->cm_fields['U']);
-       }
+       len = snprintf(recipient, sizeof(recipient), "%s@%s",
+                      msg->cm_fields[eAuthor],
+                      msg->cm_fields[eNodeName]);
 
-       msg->cm_fields['A'] = strdup(BOUNCESOURCE);
-       msg->cm_fields['N'] = strdup(config.c_nodename);
-       msg->cm_fields['U'] = strdup("Delivery Status Notification (Failure)");
+       CM_SetField(msg, eAuthor, HKEY(BOUNCESOURCE));
+       CM_SetField(msg, eNodeName, config.c_nodename, strlen(config.c_nodename));
+       CM_SetField(msg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
 
-       /* prepend our node to the path */
-       if (msg->cm_fields['P'] != NULL) {
-               oldpath = msg->cm_fields['P'];
-               msg->cm_fields['P'] = NULL;
-       }
-       else {
-               oldpath = strdup("unknown_user");
-       }
-       size = strlen(oldpath) + SIZ;
-       msg->cm_fields['P'] = malloc(size);
-       snprintf(msg->cm_fields['P'], size, "%s!%s", config.c_nodename, oldpath);
-       free(oldpath);
+       Netmap_AddMe(msg, HKEY("unknown_user"));
 
        /* Now submit the message */
        valid = validate_recipients(recipient, NULL, 0);
@@ -447,7 +416,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason)
 
        /* Clean up */
        if (valid != NULL) free_recipients(valid);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        QNM_syslog(LOG_DEBUG, "leaving network_bounce()\n");
 }
 
index 396ea5be67f29388a6d64a0ad8d64de8c7a4590f..9c1c944d9f881f542f79179b046a02333c18a032 100644 (file)
@@ -106,7 +106,7 @@ int serv_notes_beforesave(struct CtdlMessage *msg)
         * any existing message containing that UUID.
         */
        strcpy(uuid, "");
-       p = msg->cm_fields['M'];
+       p = msg->cm_fields[eMesageText];
        a = strlen(p);
        while (--a > 0) {
                if (!strncasecmp(p, "X-KOrg-Note-Id: ", 16)) {  /* Found it */
@@ -120,16 +120,9 @@ int serv_notes_beforesave(struct CtdlMessage *msg)
 
                        syslog(LOG_DEBUG, "UUID of note is: %s\n", uuid);
                        if (!IsEmptyStr(uuid)) {
+                               CM_SetField(msg, eExclusiveID, uuid, strlen(uuid));
 
-                               if (msg->cm_fields['E'] != NULL) {
-                                       free(msg->cm_fields['E']);
-                               }
-                               msg->cm_fields['E'] = strdup(uuid);
-
-                               if (msg->cm_fields['U'] != NULL) {
-                                       free(msg->cm_fields['U']);
-                               }
-                               msg->cm_fields['U'] = strdup(uuid);
+                               CM_CopyField(msg, eMsgSubject, eExclusiveID);
                        }
                }
                p++;
@@ -137,7 +130,7 @@ int serv_notes_beforesave(struct CtdlMessage *msg)
 
        /* Modern clients are using vNote format.  Check for one... */
 
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *notes_extract_vnote,
                NULL, NULL,
@@ -149,23 +142,19 @@ int serv_notes_beforesave(struct CtdlMessage *msg)
 
        /* Set the message EUID to the vNote UID */
 
-       if (v->uid) if (!IsEmptyStr(v->uid)) {
+       if ((v->uid) && (!IsEmptyStr(v->uid))) {
                syslog(LOG_DEBUG, "UID of vNote is: %s\n", v->uid);
-               if (msg->cm_fields['E'] != NULL) {
-                       free(msg->cm_fields['E']);
-               }
-               msg->cm_fields['E'] = strdup(v->uid);
+               CM_SetField(msg, eExclusiveID, v->uid, strlen(v->uid));
        }
 
        /* Set the message Subject to the vNote Summary */
 
-       if (v->summary) if (!IsEmptyStr(v->summary)) {
-               if (msg->cm_fields['U'] != NULL) {
-                       free(msg->cm_fields['U']);
-               }
-               msg->cm_fields['U'] = strdup(v->summary);
-               if (strlen(msg->cm_fields['U']) > 72) {
-                       strcpy(&msg->cm_fields['U'][68], "...");
+       if ((v->summary) && (!IsEmptyStr(v->summary))) {
+               CM_SetField(msg, eMsgSubject, v->summary, strlen(v->summary));
+
+               if (strlen(msg->cm_fields[eMsgSubject]) > 72) {
+                       strcpy(&msg->cm_fields[eMsgSubject][68], "...");
+                       CM_CutFieldAt(msg, eMsgSubject, 72);
                }
        }
 
index 8a12d15037402f33a7d000665b0b9a577e0053aa..9fe2cd6b2546badcc17c7eb7beb691aecd645d2b 100644 (file)
@@ -613,7 +613,7 @@ eNextState POP3C_SaveMsg(AsyncIO *IO)
                 * so we don't fetch this message again
                 */
        }
-       CtdlFreeMessage(RecvMsg->CurrMsg->Msg);
+       CM_Free(RecvMsg->CurrMsg->Msg);
 
        RecvMsg->count ++;
        return NextDBOperation(&RecvMsg->IO, POP3C_StoreMsgRead);
index 0a09f2c3737809b32d543d157a164fd2de8f9126..982869d314d03891198d9bc7c373a33c38cdb8ca 100644 (file)
@@ -602,7 +602,7 @@ void FreeNetworkSaveMessage (void *vMsg)
 {
        networker_save_message *Msg = (networker_save_message *) vMsg;
 
-       CtdlFreeMessageContents(&Msg->Msg);
+       CM_FreeContents(&Msg->Msg);
        FreeStrBuf(&Msg->Message);
        FreeStrBuf(&Msg->MsgGUID);
 
@@ -675,7 +675,7 @@ void rss_remember_item(rss_item *ri, rss_aggregator *RSSAggr)
        /* gather the cheaply computed information now... */
 
        if (ri->guid != NULL) {
-               SaveMsg->Msg.cm_fields['E'] = strdup(ChrPtr(ri->guid));
+               CM_SetField(&SaveMsg->Msg, eExclusiveID, SKEY(ri->guid));
        }
 
        SaveMsg->MsgGUID = guid;
@@ -683,12 +683,10 @@ void rss_remember_item(rss_item *ri, rss_aggregator *RSSAggr)
        if (ri->pubdate <= 0) {
                ri->pubdate = time(NULL); /// TODO: use event time!
        }
-       SaveMsg->Msg.cm_fields['T'] = malloc(64);
-       snprintf(SaveMsg->Msg.cm_fields['T'], 64, "%ld", ri->pubdate);
+       CM_SetFieldLONG(&SaveMsg->Msg, eTimestamp, ri->pubdate);
        if (ri->channel_title != NULL) {
                if (StrLength(ri->channel_title) > 0) {
-                       SaveMsg->Msg.cm_fields['O'] =
-                               strdup(ChrPtr(ri->channel_title));
+                       CM_SetField(&SaveMsg->Msg, eOriginalRoom, SKEY(ri->channel_title));
                }
        }
 
index acddbe9199c09ba93397db612284d057d7eb20d2..ad0f8b2c41b68f74a6d073f75ebaea01fd847d5c 100644 (file)
@@ -18,6 +18,7 @@
  * 
  */
 
+#include "internet_addressing.h"
 
 #define RSS_UNSET       (1<<0)
 #define RSS_RSS         (1<<1)
index d31a59af4dbe19283cd31dd98217e7e9e128968f..701f9717b80cdfc8c95258c8aba847f74bc10619 100644 (file)
@@ -290,6 +290,8 @@ int rss_format_item(AsyncIO *IO, networker_save_message *SaveMsg)
                return 0;
        }
 
+       memset(&SaveMsg->Msg, 0, sizeof (struct CtdlMessage));
+
        if (SaveMsg->author_or_creator != NULL) {
 
                char *From;
@@ -307,36 +309,31 @@ int rss_format_item(AsyncIO *IO, networker_save_message *SaveMsg)
                if (!FromAt && StrLength (SaveMsg->author_email) > 0)
                {
                        StrBufRFC2047encode(&Encoded, SaveMsg->author_or_creator);
-                       SaveMsg->Msg.cm_fields['A'] = SmashStrBuf(&Encoded);
-                       SaveMsg->Msg.cm_fields['P'] =
-                               SmashStrBuf(&SaveMsg->author_email);
+                       CM_SetAsFieldSB(&SaveMsg->Msg, eAuthor, &Encoded);
+                       CM_SetAsFieldSB(&SaveMsg->Msg, eMessagePath, &SaveMsg->author_email);
                }
                else
                {
                        if (FromAt)
                        {
-                               SaveMsg->Msg.cm_fields['A'] =
-                                       SmashStrBuf(&SaveMsg->author_or_creator);
-                               SaveMsg->Msg.cm_fields['P'] =
-                                       strdup(SaveMsg->Msg.cm_fields['A']);
+                               CM_SetAsFieldSB(&SaveMsg->Msg, eAuthor, &SaveMsg->author_or_creator);
+                               CM_CopyField(&SaveMsg->Msg, eMessagePath, eAuthor);
                        }
                        else
                        {
                                StrBufRFC2047encode(&Encoded,
                                                    SaveMsg->author_or_creator);
-                               SaveMsg->Msg.cm_fields['A'] =
-                                       SmashStrBuf(&Encoded);
-                               SaveMsg->Msg.cm_fields['P'] =
-                                       strdup("rss@localhost");
+                               CM_SetAsFieldSB(&SaveMsg->Msg, eAuthor, &Encoded);
+                               CM_SetField(&SaveMsg->Msg, eMessagePath, HKEY("rss@localhost"));
 
                        }
                }
        }
        else {
-               SaveMsg->Msg.cm_fields['A'] = strdup("rss");
+               CM_SetField(&SaveMsg->Msg, eAuthor, HKEY("rss"));
        }
 
-       SaveMsg->Msg.cm_fields['N'] = strdup(NODENAME);
+       CM_SetField(&SaveMsg->Msg, eNodeName, NODENAME, strlen(NODENAME));
        if (SaveMsg->title != NULL) {
                long len;
                char *Sbj;
@@ -358,7 +355,7 @@ int rss_format_item(AsyncIO *IO, networker_save_message *SaveMsg)
                StrBufTrim(Encoded);
                StrBufRFC2047encode(&QPEncoded, Encoded);
 
-               SaveMsg->Msg.cm_fields['U'] = SmashStrBuf(&QPEncoded);
+               CM_SetAsFieldSB(&SaveMsg->Msg, eMsgSubject, &QPEncoded);
                FreeStrBuf(&Encoded);
        }
        if (SaveMsg->link == NULL)
@@ -398,8 +395,8 @@ eNextState RSSSaveMessage(AsyncIO *IO)
 
        if (rss_format_item(IO, RSSAggr->ThisMsg))
        {
-               RSSAggr->ThisMsg->Msg.cm_fields['M'] =
-                       SmashStrBuf(&RSSAggr->ThisMsg->Message);
+               CM_SetAsFieldSB(&RSSAggr->ThisMsg->Msg, eMesageText,
+                                      &RSSAggr->ThisMsg->Message);
 
                CtdlSubmitMsg(&RSSAggr->ThisMsg->Msg, &RSSAggr->recp, NULL, 0);
                
index abce872ce89660de12afaf7d4962db47d354140a..ecdaafd78b819b8e19ee9f80c7ae21f1b3409291 100644 (file)
@@ -134,7 +134,7 @@ int ctdl_redirect(sieve2_context_t *s, void *my)
        CtdlSubmitMsg(msg, valid, NULL, 0);
        cs->cancel_implicit_keep = 1;
        free_recipients(valid);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        return SIEVE2_OK;
 }
 
@@ -583,37 +583,37 @@ void sieve_do_msg(long msgnum, void *userdata) {
        my.u = u;                               /* Hand off a pointer to the rest of this info */
 
        /* Keep track of the recipient so we can do handling based on it later */
-       process_rfc822_addr(msg->cm_fields['R'], my.recp_user, my.recp_node, my.recp_name);
+       process_rfc822_addr(msg->cm_fields[eRecipient], my.recp_user, my.recp_node, my.recp_name);
 
        /* Keep track of the sender so we can use it for REJECT and VACATION responses */
-       if (msg->cm_fields['F'] != NULL) {
-               safestrncpy(my.sender, msg->cm_fields['F'], sizeof my.sender);
+       if (!CM_IsEmpty(msg, erFc822Addr)) {
+               safestrncpy(my.sender, msg->cm_fields[erFc822Addr], sizeof my.sender);
        }
-       else if ( (msg->cm_fields['A'] != NULL) && (msg->cm_fields['N'] != NULL) ) {
-               snprintf(my.sender, sizeof my.sender, "%s@%s", msg->cm_fields['A'], msg->cm_fields['N']);
+       else if ( (!CM_IsEmpty(msg, eAuthor)) && (!CM_IsEmpty(msg, eNodeName)) ) {
+               snprintf(my.sender, sizeof my.sender, "%s@%s", msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]);
        }
-       else if (msg->cm_fields['A'] != NULL) {
-               safestrncpy(my.sender, msg->cm_fields['A'], sizeof my.sender);
+       else if (!CM_IsEmpty(msg, eAuthor)) {
+               safestrncpy(my.sender, msg->cm_fields[eAuthor], sizeof my.sender);
        }
        else {
                strcpy(my.sender, "");
        }
 
        /* Keep track of the subject so we can use it for VACATION responses */
-       if (msg->cm_fields['U'] != NULL) {
-               safestrncpy(my.subject, msg->cm_fields['U'], sizeof my.subject);
+       if (!CM_IsEmpty(msg, eMsgSubject)) {
+               safestrncpy(my.subject, msg->cm_fields[eMsgSubject], sizeof my.subject);
        }
        else {
                strcpy(my.subject, "");
        }
 
        /* Keep track of the envelope-from address (use body-from if not found) */
-       if (msg->cm_fields['P'] != NULL) {
-               safestrncpy(my.envelope_from, msg->cm_fields['P'], sizeof my.envelope_from);
+       if (!CM_IsEmpty(msg, eMessagePath)) {
+               safestrncpy(my.envelope_from, msg->cm_fields[eMessagePath], sizeof my.envelope_from);
                stripallbut(my.envelope_from, '<', '>');
        }
-       else if (msg->cm_fields['F'] != NULL) {
-               safestrncpy(my.envelope_from, msg->cm_fields['F'], sizeof my.envelope_from);
+       else if (!CM_IsEmpty(msg, erFc822Addr)) {
+               safestrncpy(my.envelope_from, msg->cm_fields[erFc822Addr], sizeof my.envelope_from);
                stripallbut(my.envelope_from, '<', '>');
        }
        else {
@@ -630,15 +630,15 @@ void sieve_do_msg(long msgnum, void *userdata) {
        }
 
        /* Keep track of the envelope-to address (use body-to if not found) */
-       if (msg->cm_fields['V'] != NULL) {
-               safestrncpy(my.envelope_to, msg->cm_fields['V'], sizeof my.envelope_to);
+       if (!CM_IsEmpty(msg, eenVelopeTo)) {
+               safestrncpy(my.envelope_to, msg->cm_fields[eenVelopeTo], sizeof my.envelope_to);
                stripallbut(my.envelope_to, '<', '>');
        }
-       else if (msg->cm_fields['R'] != NULL) {
-               safestrncpy(my.envelope_to, msg->cm_fields['R'], sizeof my.envelope_to);
-               if (msg->cm_fields['D'] != NULL) {
+       else if (!CM_IsEmpty(msg, eRecipient)) {
+               safestrncpy(my.envelope_to, msg->cm_fields[eRecipient], sizeof my.envelope_to);
+               if (!CM_IsEmpty(msg, eDestination)) {
                        strcat(my.envelope_to, "@");
-                       strcat(my.envelope_to, msg->cm_fields['D']);
+                       strcat(my.envelope_to, msg->cm_fields[eDestination]);
                }
                stripallbut(my.envelope_to, '<', '>');
        }
@@ -655,7 +655,7 @@ void sieve_do_msg(long msgnum, void *userdata) {
                strcat(my.envelope_to, config.c_fqdn);
        }
 
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        
        SVM_syslog(LOG_DEBUG, "Calling sieve2_execute()");
        res = sieve2_execute(sieve2_context, &my);
@@ -746,6 +746,7 @@ void get_sieve_config_backend(long msgnum, void *userdata) {
        struct sdm_userdata *u = (struct sdm_userdata *) userdata;
        struct CtdlMessage *msg;
        char *conf;
+       long conflen;
 
        u->config_msgnum = msgnum;
        msg = CtdlFetchMessage(msgnum, 1);
@@ -754,9 +755,9 @@ void get_sieve_config_backend(long msgnum, void *userdata) {
                return;
        }
 
-       conf = msg->cm_fields['M'];
-       msg->cm_fields['M'] = NULL;
-       CtdlFreeMessage(msg);
+       CM_GetAsField(msg, eMesageText, &conf, &conflen);
+
+       CM_Free(msg);
 
        if (conf != NULL) {
                parse_sieve_config(conf, u);
index be6347466270576c957d1610d8c29e1d3b5a961c..4eec7e85d5852400de7e4cb750b189082c7eef48 100644 (file)
@@ -69,6 +69,7 @@
 #include "config.h"
 #include "control.h"
 #include "user_ops.h"
+#include "room_ops.h"
 #include "database.h"
 #include "msgbase.h"
 #include "internet_addressing.h"
@@ -322,12 +323,14 @@ void smtp_webcit_preferences_hack_backend(long msgnum, void *userdata) {
                return;
        }
 
-       if ( (msg->cm_fields['U']) && (!strcasecmp(msg->cm_fields['U'], "__ WebCit Preferences __")) ) {
+       if ( !CM_IsEmpty(msg, eMsgSubject) &&
+            (!strcasecmp(msg->cm_fields[eMsgSubject], "__ WebCit Preferences __")))
+       {
                /* This is it!  Change ownership of the message text so it doesn't get freed. */
-               *webcit_conf = (char *)msg->cm_fields['M'];
-               msg->cm_fields['M'] = NULL;
+               *webcit_conf = (char *)msg->cm_fields[eMesageText];
+               msg->cm_fields[eMesageText] = NULL;
        }
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
@@ -830,12 +833,12 @@ void smtp_data(long offset, long flags)
        if ( (CCC->logged_in) && (config.c_rfc822_strict_from != CFG_SMTP_FROM_NOFILTER) ) {
                int validemail = 0;
                
-               if (!IsEmptyStr(msg->cm_fields['F'])       &&
+               if (!CM_IsEmpty(msg, erFc822Addr)       &&
                    ((config.c_rfc822_strict_from == CFG_SMTP_FROM_CORRECT) || 
                     (config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT)    )  )
                {
                        if (!IsEmptyStr(CCC->cs_inet_email))
-                               validemail = strcmp(CCC->cs_inet_email, msg->cm_fields['F']) == 0;
+                               validemail = strcmp(CCC->cs_inet_email, msg->cm_fields[erFc822Addr]) == 0;
                        if ((!validemail) && 
                            (!IsEmptyStr(CCC->cs_inet_other_emails)))
                        {
@@ -845,52 +848,38 @@ void smtp_data(long offset, long flags)
                                for (i=0; i < num_secondary_emails && !validemail; ++i) {
                                        char buf[256];
                                        extract_token(buf, CCC->cs_inet_other_emails,i,'|',sizeof CCC->cs_inet_other_emails);
-                                       validemail = strcmp(buf, msg->cm_fields['F']) == 0;
+                                       validemail = strcmp(buf, msg->cm_fields[erFc822Addr]) == 0;
                                }
                        }
                }
 
                if (!validemail && (config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT)) {
-                       syslog(LOG_ERR, "invalid sender '%s' - rejecting this message", msg->cm_fields['F']);
-                       cprintf("550 Invalid sender '%s' - rejecting this message.\r\n", msg->cm_fields['F']);
+                       syslog(LOG_ERR, "invalid sender '%s' - rejecting this message", msg->cm_fields[erFc822Addr]);
+                       cprintf("550 Invalid sender '%s' - rejecting this message.\r\n", msg->cm_fields[erFc822Addr]);
                        return;
                }
 
-               if (msg->cm_fields['A'] != NULL) free(msg->cm_fields['A']);
-               if (msg->cm_fields['N'] != NULL) free(msg->cm_fields['N']);
-               if (msg->cm_fields['H'] != NULL) free(msg->cm_fields['H']);
-               if (msg->cm_fields['O'] != NULL) free(msg->cm_fields['O']);
-               msg->cm_fields['N'] = strdup(config.c_nodename);
-               msg->cm_fields['H'] = strdup(config.c_humannode);
-               msg->cm_fields['O'] = strdup(MAILROOM);
-
-               msg->cm_fields['A'] =
-                       ((sSMTP->preferred_sender_name != NULL)
-                       ? strdup(ChrPtr(sSMTP->preferred_sender_name)) 
-                       : strdup(CCC->user.fullname)
-               );
+               CM_SetField(msg, eNodeName, config.c_nodename, strlen(config.c_nodename));
+               CM_SetField(msg, eHumanNode, config.c_humannode, strlen(config.c_humannode));
+               CM_SetField(msg, eOriginalRoom, HKEY(MAILROOM));
+               if (sSMTP->preferred_sender_name != NULL)
+                       CM_SetFieldSB(msg, eAuthor, sSMTP->preferred_sender_name);
+               else 
+                       CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
 
                if (!validemail) {
-                       if (msg->cm_fields['F'] != NULL) free(msg->cm_fields['F']);
-                       msg->cm_fields['F'] = 
-                               ((sSMTP->preferred_sender_email != NULL)
-                               ? strdup(ChrPtr(sSMTP->preferred_sender_email)) 
-                               : strdup(CCC->cs_inet_email)
-                       );
+                       if((sSMTP->preferred_sender_email != NULL)
+                               CM_SetFieldSB(msg, erFc822Addr, sSMTP->preferred_sender_email)) 
+                       else
+                               CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email));
                }
        }
 
        /* Set the "envelope from" address */
-       if (msg->cm_fields['P'] != NULL) {
-               free(msg->cm_fields['P']);
-       }
-       msg->cm_fields['P'] = strdup(ChrPtr(sSMTP->from));
+       CM_SetField(msg, eMessagePath, SKEY(sSMTP->from));
 
        /* Set the "envelope to" address */
-       if (msg->cm_fields['V'] != NULL) {
-               free(msg->cm_fields['V']);
-       }
-       msg->cm_fields['V'] = strdup(ChrPtr(sSMTP->recipients));
+       CM_SetField(msg, eenVelopeTo, SKEY(sSMTP->recipients));
 
        /* Submit the message into the Citadel system. */
        valid = validate_recipients(
@@ -912,11 +901,11 @@ void smtp_data(long offset, long flags)
 
        if (scan_errors > 0) {  /* We don't want this message! */
 
-               if (msg->cm_fields['0'] == NULL) {
-                       msg->cm_fields['0'] = strdup("Message rejected by filter");
+               if (CM_IsEmpty(msg, eErrorMsg)) {
+                       CM_SetField(msg, eErrorMsg, HKEY("Message rejected by filter"));
                }
 
-               StrBufPrintf(sSMTP->OneRcpt, "550 %s\r\n", msg->cm_fields['0']);
+               StrBufPrintf(sSMTP->OneRcpt, "550 %s\r\n", msg->cm_fields[eErrorMsg]);
        }
        
        else {                  /* Ok, we'll accept this message. */
@@ -958,7 +947,7 @@ void smtp_data(long offset, long flags)
        );
 
        /* Clean up */
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        free_recipients(valid);
        smtp_data_clear(0, 0);  /* clear out the buffers now */
 }
index 209c964b2aff885ef03ee8cd0ba6a61f9b37b024..47c1d605e525c213424501448f51e3d3d2e3335a 100644 (file)
@@ -222,12 +222,12 @@ eNextState FinalizeMessageSend_DB(AsyncIO *IO)
                msg->cm_magic = CTDLMESSAGE_MAGIC;
                msg->cm_anon_type = MES_NORMAL;
                msg->cm_format_type = FMT_RFC822;
-               msg->cm_fields['M'] = SmashStrBuf(&Msg->QMsgData);
-               msg->cm_fields['U'] = strdup("QMSG");
+               CM_SetAsFieldSB(msg, eMesageText, &Msg->QMsgData);
+               CM_SetField(msg, eMsgSubject, HKEY("QMSG"));
                Msg->MyQItem->QueMsgID =
                        CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR);
                EVS_syslog(LOG_DEBUG, "%ld", Msg->MyQItem->QueMsgID);
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
        }
        else {
                CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM,
index 52433b90f3fe6e7629d9b11673f1e55fc53e4421..1a5761b6bf720d3bb25fb1d864cd7f8d1be0534d 100644 (file)
@@ -700,11 +700,11 @@ void smtpq_do_bounce(OneQueItem *MyQItem, StrBuf *OMsgTxt, ParsedURL *Relay)
        bmsg->cm_anon_type = MES_NORMAL;
        bmsg->cm_format_type = FMT_RFC822;
 
-       bmsg->cm_fields['O'] = strdup(MAILROOM);
-       bmsg->cm_fields['A'] = strdup("Citadel");
-       bmsg->cm_fields['N'] = strdup(config.c_nodename);
-       bmsg->cm_fields['U'] = strdup("Delivery Status Notification (Failure)");
-       bmsg->cm_fields['M'] = SmashStrBuf(&BounceMB);
+       CM_SetField(bmsg, eOriginalRoom, HKEY(MAILROOM));
+       CM_SetField(bmsg, eAuthor, HKEY("Citadel"));
+       CM_SetField(bmsg, eNodeName, config.c_nodename, strlen(config.c_nodename));
+       CM_SetField(bmsg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
+       CM_SetAsFieldSB(bmsg, eMesageText, &BounceMB);
 
        /* First try the user who sent the message */
        if (StrLength(MyQItem->BounceTo) == 0) {
@@ -730,7 +730,7 @@ void smtpq_do_bounce(OneQueItem *MyQItem, StrBuf *OMsgTxt, ParsedURL *Relay)
        /* Free up the memory we used */
        free_recipients(valid);
        FreeStrBuf(&boundary);
-       CtdlFreeMessage(bmsg);
+       CM_Free(bmsg);
        SMTPCM_syslog(LOG_DEBUG, "Done processing bounces\n");
 }
 
@@ -848,7 +848,7 @@ void smtp_do_procmsg(long msgnum, void *userdata) {
                return;
        }
 
-       pch = instr = msg->cm_fields['M'];
+       pch = instr = msg->cm_fields[eMesageText];
 
        /* Strip out the headers (no not amd any other non-instruction) line */
        while (pch != NULL) {
@@ -859,7 +859,7 @@ void smtp_do_procmsg(long msgnum, void *userdata) {
                }
        }
        PlainQItem = NewStrBufPlain(instr, -1);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        MyQItem = DeserializeQueueItem(PlainQItem, msgnum);
        FreeStrBuf(&PlainQItem);
 
index 1c57d99595de161d134ac06a597fe3b5ac30c4a5..dae60b6daf14a8d46f2c457d9fbcfd69ddca4302 100644 (file)
@@ -161,10 +161,10 @@ void smtp_do_bounce(char *instr, StrBuf *OMsgTxt)
        bmsg->cm_magic = CTDLMESSAGE_MAGIC;
        bmsg->cm_anon_type = MES_NORMAL;
        bmsg->cm_format_type = FMT_RFC822;
-       bmsg->cm_fields['A'] = strdup("Citadel");
-       bmsg->cm_fields['O'] = strdup(MAILROOM);
-       bmsg->cm_fields['N'] = strdup(config.c_nodename);
-       bmsg->cm_fields['U'] = strdup("Delivery Status Notification (Failure)");
+       CM_SetField(bmsg, eAuthor, HKEY("Citadel"));
+       CM_SetField(bmsg, eOriginalRoom, HKEY(MAILROOM));
+       CM_SetField(bmsg, eNodeName, config.c_nodename, strlen(config.c_nodename));
+       CM_SetField(bmsg, eMsgSubject, HKEY("Delivery Status Notification (Failure)"));
        StrBufAppendBufPlain(
                BounceMB,
                HKEY("Content-type: multipart/mixed; boundary=\""), 0);
@@ -286,9 +286,8 @@ void smtp_do_bounce(char *instr, StrBuf *OMsgTxt)
        StrBufAppendBufPlain(BounceMB, HKEY("--"), 0);
        StrBufAppendBuf(BounceMB, boundary, 0);
        StrBufAppendBufPlain(BounceMB, HKEY("--\r\n"), 0);
-       if (bmsg->cm_fields['M'] != NULL)
-               free(bmsg->cm_fields['M']);
-       bmsg->cm_fields['M'] = SmashStrBuf(&BounceMB);
+       CM_SetAsFieldSB(bmsg, eMesageText, &BounceMB);
+
        /* Deliver the bounce if there's anything worth mentioning */
        syslog(LOG_DEBUG, "num_bounces = %d\n", num_bounces);
        if (num_bounces > 0) {
@@ -320,6 +319,6 @@ void smtp_do_bounce(char *instr, StrBuf *OMsgTxt)
                }
        }
        FreeStrBuf(&boundary);
-       CtdlFreeMessage(bmsg);
+       CM_Free(bmsg);
        syslog(LOG_DEBUG, "Done processing bounces\n");
 }
index 7c24672ef4b2b1d5bd5d8f2541e649b6bc18b0ec..77365b16c3844735e16340dcb3d6f463d9a8a962 100644 (file)
@@ -143,35 +143,31 @@ int spam_assassin(struct CtdlMessage *msg) {
         syslog(LOG_DEBUG, "<%s\n", buf);
         syslog(LOG_DEBUG, "c_spam_flag_only setting %d\n", config.c_spam_flag_only);
         if (config.c_spam_flag_only) {
-                syslog(LOG_DEBUG, "flag spam code used");
                int headerlen;
-               int newmsgsize;
-               int oldmsgsize;
-
+               char *cur;
                char sastatus[10];
                char sascore[10];
                char saoutof[10];
                int numscore;
 
+                syslog(LOG_DEBUG, "flag spam code used");
+
                 extract_token(sastatus, buf, 1, ' ', sizeof sastatus);
                 extract_token(sascore, buf, 3, ' ', sizeof sascore);
                 extract_token(saoutof, buf, 5, ' ', sizeof saoutof);
 
-               sprintf(buf,"X-Spam-Level: ");
-               char *cur = buf + 14;
+               memcpy(buf, HKEY("X-Spam-Level: "));
+               cur = buf + 14;
                for (numscore = atoi(sascore); numscore>0; numscore--)
                        *(cur++) = '*';
                *cur = '\0';
 
-               sprintf(cur,"\r\nX-Spam-Status: %s, score=%s required=%s\r\n", sastatus, sascore, saoutof);
-               headerlen = strlen(buf);
-               oldmsgsize = strlen(msg->cm_fields['M']) + 1;
-               newmsgsize = headerlen + oldmsgsize;
-
-               msg->cm_fields['M'] = realloc(msg->cm_fields['M'], newmsgsize);
+               headerlen  = cur - buf;
+               headerlen += snprintf(cur, (sizeof(buf) - headerlen), 
+                                    "\r\nX-Spam-Status: %s, score=%s required=%s\r\n",
+                                    sastatus, sascore, saoutof);
 
-               memmove(msg->cm_fields['M']+headerlen,msg->cm_fields['M'],oldmsgsize);
-               memcpy(msg->cm_fields['M'],buf,headerlen);
+               CM_PrependToField(msg, eMesageText, buf, headerlen);
 
        } else {
                 syslog(LOG_DEBUG, "reject spam code used");
@@ -180,10 +176,7 @@ int spam_assassin(struct CtdlMessage *msg) {
                }
 
                if (is_spam) {
-                       if (msg->cm_fields['0'] != NULL) {
-                               free(msg->cm_fields['0']);
-                       }
-                       msg->cm_fields['0'] = strdup("message rejected by spam filter");
+                       CM_SetField(msg, eErrorMsg, HKEY("message rejected by spam filter"));
                }
        }
 
index 1512c66b7652d77bcaab3400a1641bfe30672881..393cf72101fbfd3fc1d1ebc58810234b6b7df84c 100644 (file)
@@ -63,6 +63,7 @@
 #include "user_ops.h"
 #include "database.h"
 #include "msgbase.h"
+#include "room_ops.h"
 #include "internet_addressing.h"
 #include "serv_vcard.h"
 #include "citadel_ldap.h"
@@ -94,12 +95,12 @@ void vcard_extract_internet_addresses(struct CtdlMessage *msg, int (*callback)(c
        int instance = 0;
        int found_something = 0;
 
-       if (msg->cm_fields['A'] == NULL) return;
-       if (msg->cm_fields['N'] == NULL) return;
+       if (CM_IsEmpty(msg, eAuthor)) return;
+       if (CM_IsEmpty(msg, eNodeName)) return;
        snprintf(citadel_address, sizeof citadel_address, "%s @ %s",
-               msg->cm_fields['A'], msg->cm_fields['N']);
+               msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]);
 
-       v = vcard_load(msg->cm_fields['M']);
+       v = vcard_load(msg->cm_fields[eMesageText]);
        if (v == NULL) return;
 
        /* Go through the vCard searching for *all* instances of
@@ -189,7 +190,7 @@ void vcard_add_to_directory(long msgnum, void *data) {
                vcard_extract_internet_addresses(msg, vcard_directory_add_user);
        }
 
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
@@ -330,7 +331,6 @@ void vcard_extract_vcard(char *name, char *filename, char *partnum, char *disp,
  */
 int vcard_upload_beforesave(struct CtdlMessage *msg) {
        struct CitContext *CCC = CC;
-       char *ptr;
        char *s;
        char buf[SIZ];
        struct ctdluser usbuf;
@@ -373,10 +373,9 @@ int vcard_upload_beforesave(struct CtdlMessage *msg) {
 
        /* Ok, if we got this far, look into the situation further... */
 
-       ptr = msg->cm_fields['M'];
-       if (ptr == NULL) return(0);
+       if (CM_IsEmpty(msg, eMesageText)) return(0);
 
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *vcard_extract_vcard,
                NULL, NULL,
@@ -425,10 +424,7 @@ int vcard_upload_beforesave(struct CtdlMessage *msg) {
                CtdlDeleteMessages(CCC->room.QRname, NULL, 0, "[Tt][Ee][Xx][Tt]/.*[Vv][Cc][Aa][Rr][Dd]$");
 
                /* Make the author of the message the name of the user. */
-               if (msg->cm_fields['A'] != NULL) {
-                       free(msg->cm_fields['A']);
-               }
-               msg->cm_fields['A'] = strdup(usbuf.fullname);
+               CM_SetField(msg, eAuthor, usbuf.fullname, strlen(usbuf.fullname));
        }
 
        /* Insert or replace RFC2739-compliant free/busy URL */
@@ -451,23 +447,20 @@ int vcard_upload_beforesave(struct CtdlMessage *msg) {
 
        /* Enforce local UID policy if applicable */
        if (yes_my_citadel_config) {
-               snprintf(buf, sizeof buf, VCARD_EXT_FORMAT, msg->cm_fields['A'], NODENAME);
+               snprintf(buf, sizeof buf, VCARD_EXT_FORMAT, msg->cm_fields[eAuthor], NODENAME);
                vcard_set_prop(v, "UID", buf, 0);
        }
 
        /* 
         * Set the EUID of the message to the UID of the vCard.
         */
-       if (msg->cm_fields['E'] != NULL)
-       {
-               free(msg->cm_fields['E']);
-               msg->cm_fields['E'] = NULL;
-       }
+       CM_FlushField(msg, eExclusiveID);
+
        s = vcard_get_prop(v, "UID", 1, 0, 0);
        if (s != NULL) {
-               msg->cm_fields['E'] = strdup(s);
-               if (msg->cm_fields['U'] == NULL) {
-                       msg->cm_fields['U'] = strdup(s);
+               CM_SetField(msg, eExclusiveID, s, strlen(s));
+               if (CM_IsEmpty(msg, eMsgSubject)) {
+                       CM_CopyField(msg, eMsgSubject, eExclusiveID);
                }
        }
 
@@ -479,19 +472,22 @@ int vcard_upload_beforesave(struct CtdlMessage *msg) {
                s = vcard_get_prop(v, "N", 1, 0, 0);
        }
        if (s != NULL) {
-               if (msg->cm_fields['U'] != NULL) {
-                       free(msg->cm_fields['U']);
-               }
-               msg->cm_fields['U'] = strdup(s);
+               CM_SetField(msg, eMsgSubject, s, strlen(s));
        }
 
        /* Re-serialize it back into the msg body */
        ser = vcard_serialize(v);
        if (ser != NULL) {
-               msg->cm_fields['M'] = realloc(msg->cm_fields['M'], strlen(ser) + 1024);
-               sprintf(msg->cm_fields['M'],
-                       "Content-type: " VCARD_MIME_TYPE
-                       "\r\n\r\n%s\r\n", ser);
+               StrBuf *buf;
+               long serlen;
+
+               serlen = strlen(ser);
+               buf = NewStrBufPlain(NULL, serlen + 1024);
+
+               StrBufAppendBufPlain(buf, HKEY("Content-type: " VCARD_MIME_TYPE "\r\n\r\n"), 0);
+               StrBufAppendBufPlain(buf, ser, serlen, 0);
+               StrBufAppendBufPlain(buf, HKEY("\r\n"), 0);
+               CM_SetAsFieldSB(msg, eMesageText, &buf);
                free(ser);
        }
 
@@ -538,8 +534,10 @@ int vcard_upload_aftersave(struct CtdlMessage *msg) {
 
        if (!is_UserConf && !is_GAB) return(0);
 
-       ptr = msg->cm_fields['M'];
-       if (ptr == NULL) return(0);
+       if (CM_IsEmpty(msg, eMesageText))
+               return 0;
+
+       ptr = msg->cm_fields[eMesageText];
 
        NewStrBufDupAppendFlush(&CCC->StatusMessage, NULL, NULL, 0);
 
@@ -557,12 +555,12 @@ int vcard_upload_aftersave(struct CtdlMessage *msg) {
                         * copy it to the Global Address Book room.
                         */
 
-                       I = atol(msg->cm_fields['3']);
+                       I = atol(msg->cm_fields[eVltMsgNum]);
                        if (I <= 0L) return(0);
 
                        /* Store our Internet return address in memory */
                        if (is_MY_UserConf) {
-                               v = vcard_load(msg->cm_fields['M']);
+                               v = vcard_load(msg->cm_fields[eMesageText]);
                                extract_inet_email_addrs(CCC->cs_inet_email, sizeof CCC->cs_inet_email,
                                                CCC->cs_inet_other_emails, sizeof CCC->cs_inet_other_emails,
                                                v, 1);
@@ -652,8 +650,8 @@ struct vCard *vcard_get_user(struct ctdluser *u) {
        msg = CtdlFetchMessage(VCmsgnum, 1);
        if (msg == NULL) return vcard_new();
 
-       v = vcard_load(msg->cm_fields['M']);
-       CtdlFreeMessage(msg);
+       v = vcard_load(msg->cm_fields[eMesageText]);
+       CM_Free(msg);
        return v;
 }
 
@@ -897,6 +895,7 @@ void vcard_newuser(struct ctdluser *usbuf) {
 void vcard_purge(struct ctdluser *usbuf) {
        struct CtdlMessage *msg;
        char buf[SIZ];
+       long len;
 
        msg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
        if (msg == NULL) return;
@@ -905,19 +904,19 @@ void vcard_purge(struct ctdluser *usbuf) {
        msg->cm_magic = CTDLMESSAGE_MAGIC;
        msg->cm_anon_type = MES_NORMAL;
        msg->cm_format_type = 0;
-       msg->cm_fields['A'] = strdup(usbuf->fullname);
-       msg->cm_fields['O'] = strdup(ADDRESS_BOOK_ROOM);
-       msg->cm_fields['N'] = strdup(NODENAME);
-       msg->cm_fields['M'] = strdup("Purge this vCard\n");
+       CM_SetField(msg, eAuthor, usbuf->fullname, strlen(usbuf->fullname));
+       CM_SetField(msg, eOriginalRoom, HKEY(ADDRESS_BOOK_ROOM));
+       CM_SetField(msg, eNodeName, NODENAME, strlen(NODENAME));
+       CM_SetField(msg, eMesageText, HKEY("Purge this vCard\n"));
 
-       snprintf(buf, sizeof buf, VCARD_EXT_FORMAT,
-                       msg->cm_fields['A'], NODENAME);
-       msg->cm_fields['E'] = strdup(buf);
+       len = snprintf(buf, sizeof buf, VCARD_EXT_FORMAT,
+                      msg->cm_fields[eAuthor], NODENAME);
+       CM_SetField(msg, eExclusiveID, buf, len);
 
-       msg->cm_fields['S'] = strdup("CANCEL");
+       CM_SetField(msg, eSpecialField, HKEY("CANCEL"));
 
        CtdlSubmitMsg(msg, NULL, ADDRESS_BOOK_ROOM, QP_EADDR);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
@@ -936,8 +935,11 @@ int vcard_extract_from_network(struct CtdlMessage *msg, char *target_room) {
 
        if (msg->cm_format_type != 4) return(0);
 
-       ptr = msg->cm_fields['M'];
-       if (ptr == NULL) return(0);
+       if (CM_IsEmpty(msg, eMesageText))
+               return 0;
+
+       ptr = msg->cm_fields[eMesageText];
+
        while (ptr != NULL) {
        
                linelen = strcspn(ptr, "\n");
@@ -979,8 +981,11 @@ void vcard_delete_remove(char *room, long msgnum) {
        msg = CtdlFetchMessage(msgnum, 1);
        if (msg == NULL) return;
 
-       ptr = msg->cm_fields['M'];
-       if (ptr == NULL) goto EOH;
+       if (CM_IsEmpty(msg, eMesageText))
+               goto EOH;
+
+       ptr = msg->cm_fields[eMesageText];
+
        while (ptr != NULL) {
                linelen = strcspn(ptr, "\n");
                if (linelen == 0) goto EOH;
@@ -994,7 +999,7 @@ void vcard_delete_remove(char *room, long msgnum) {
                if (ptr != NULL) ++ptr;
        }
 
-EOH:   CtdlFreeMessage(msg);
+EOH:   CM_Free(msg);
 }
 
 
@@ -1102,14 +1107,14 @@ void dvca_callback(long msgnum, void *userdata) {
 
        msg = CtdlFetchMessage(msgnum, 1);
        if (msg == NULL) return;
-       mime_parser(msg->cm_fields['M'],
+       mime_parser(msg->cm_fields[eMesageText],
                NULL,
                *dvca_mime_callback,    /* callback function */
                NULL, NULL,
                NULL,                   /* user data */
                0
        );
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
@@ -1325,8 +1330,8 @@ void strip_addresses_already_have(long msgnum, void *userdata) {
 
        msg = CtdlFetchMessage(msgnum, 1);
        if (msg == NULL) return;
-       v = vcard_load(msg->cm_fields['M']);
-       CtdlFreeMessage(msg);
+       v = vcard_load(msg->cm_fields[eMesageText]);
+       CM_Free(msg);
 
        i = 0;
        while (value = vcard_get_prop(v, "email", 1, i++, 0), value != NULL) {
@@ -1372,26 +1377,34 @@ void store_this_ha(struct addresses_to_be_filed *aptr) {
                striplt(recipient);
                v = vcard_new_from_rfc822_addr(recipient);
                if (v != NULL) {
+                       const char *s;
                        vmsg = malloc(sizeof(struct CtdlMessage));
                        memset(vmsg, 0, sizeof(struct CtdlMessage));
                        vmsg->cm_magic = CTDLMESSAGE_MAGIC;
                        vmsg->cm_anon_type = MES_NORMAL;
                        vmsg->cm_format_type = FMT_RFC822;
-                       vmsg->cm_fields['A'] = strdup("Citadel");
-                       vmsg->cm_fields['E'] =  strdup(vcard_get_prop(v, "UID", 1, 0, 0));
+                       CM_SetField(vmsg, eAuthor, HKEY("Citadel"));
+                       s = vcard_get_prop(v, "UID", 1, 0, 0);
+                       CM_SetField(vmsg, eExclusiveID, s, strlen(s));
                        ser = vcard_serialize(v);
                        if (ser != NULL) {
-                               vmsg->cm_fields['M'] = malloc(strlen(ser) + 1024);
-                               sprintf(vmsg->cm_fields['M'],
-                                       "Content-type: " VCARD_MIME_TYPE
-                                       "\r\n\r\n%s\r\n", ser);
+                               StrBuf *buf;
+                               long serlen;
+                               
+                               serlen = strlen(ser);
+                               buf = NewStrBufPlain(NULL, serlen + 1024);
+
+                               StrBufAppendBufPlain(buf, HKEY("Content-type: " VCARD_MIME_TYPE "\r\n\r\n"), 0);
+                               StrBufAppendBufPlain(buf, ser, serlen, 0);
+                               StrBufAppendBufPlain(buf, HKEY("\r\n"), 0);
+                               CM_SetAsFieldSB(vmsg, eMesageText, &buf);
                                free(ser);
                        }
                        vcard_free(v);
 
                        syslog(LOG_DEBUG, "Adding contact: %s", recipient);
                        CtdlSubmitMsg(vmsg, NULL, aptr->roomname, QP_EADDR);
-                       CtdlFreeMessage(vmsg);
+                       CM_Free(vmsg);
                }
        }
 
index 07e5eed41e231aca188764b375681559b62d8692..79a961f451ed1ae289435db0586cbb8dcef6f107 100644 (file)
@@ -45,6 +45,7 @@
 #include "config.h"
 #include "control.h"
 #include "user_ops.h"
+#include "room_ops.h"
 #include "database.h"
 #include "msgbase.h"
 #include "euidindex.h"
@@ -82,6 +83,7 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
        FILE *fp;
        int rv;
        char history_page[1024];
+       long history_page_len;
        char boundary[256];
        char prefixed_boundary[258];
        char buf[1024];
@@ -100,31 +102,29 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
        if (msg->cm_format_type != 4) return(0);
 
        /* If there's no EUID we can't do this.  Reject the post. */
-       if (msg->cm_fields['E'] == NULL) return(1);
+       if (CM_IsEmpty(msg, eExclusiveID)) return(1);
 
-       snprintf(history_page, sizeof history_page, "%s_HISTORY_", msg->cm_fields['E']);
+       history_page_len = snprintf(history_page, sizeof history_page,
+                                   "%s_HISTORY_", msg->cm_fields[eExclusiveID]);
 
        /* Make sure we're saving a real wiki page rather than a wiki history page.
         * This is important in order to avoid recursing infinitely into this hook.
         */
-       if (    (strlen(msg->cm_fields['E']) >= 9)
-               && (!strcasecmp(&msg->cm_fields['E'][strlen(msg->cm_fields['E'])-9], "_HISTORY_"))
+       if (    (strlen(msg->cm_fields[eExclusiveID]) >= 9)
+               && (!strcasecmp(&msg->cm_fields[eExclusiveID][strlen(msg->cm_fields[eExclusiveID])-9], "_HISTORY_"))
        ) {
                syslog(LOG_DEBUG, "History page not being historied\n");
                return(0);
        }
 
        /* If there's no message text, obviously this is all b0rken and shouldn't happen at all */
-       if (msg->cm_fields['M'] == NULL) return(0);
+       if (CM_IsEmpty(msg, eMesageText)) return(0);
 
        /* Set the message subject identical to the page name */
-       if (msg->cm_fields['U'] != NULL) {
-               free(msg->cm_fields['U']);
-       }
-       msg->cm_fields['U'] = strdup(msg->cm_fields['E']);
+       CM_CopyField(msg, eMsgSubject, eExclusiveID);
 
        /* See if we can retrieve the previous version. */
-       old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields['E'], &CCC->room);
+       old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields[eExclusiveID], &CCC->room);
        if (old_msgnum > 0L) {
                old_msg = CtdlFetchMessage(old_msgnum, 1);
        }
@@ -132,14 +132,14 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
                old_msg = NULL;
        }
 
-       if ((old_msg != NULL) && (old_msg->cm_fields['M'] == NULL)) {   /* old version is corrupt? */
-               CtdlFreeMessage(old_msg);
+       if ((old_msg != NULL) && (CM_IsEmpty(old_msg, eMesageText))) {  /* old version is corrupt? */
+               CM_Free(old_msg);
                old_msg = NULL;
        }
        
        /* If no changes were made, don't bother saving it again */
-       if ((old_msg != NULL) && (!strcmp(msg->cm_fields['M'], old_msg->cm_fields['M']))) {
-               CtdlFreeMessage(old_msg);
+       if ((old_msg != NULL) && (!strcmp(msg->cm_fields[eMesageText], old_msg->cm_fields[eMesageText]))) {
+               CM_Free(old_msg);
                return(1);
        }
 
@@ -152,13 +152,13 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
 
        if (old_msg != NULL) {
                fp = fopen(diff_old_filename, "w");
-               rv = fwrite(old_msg->cm_fields['M'], strlen(old_msg->cm_fields['M']), 1, fp);
+               rv = fwrite(old_msg->cm_fields[eMesageText], strlen(old_msg->cm_fields[eMesageText]), 1, fp);
                fclose(fp);
-               CtdlFreeMessage(old_msg);
+               CM_Free(old_msg);
        }
 
        fp = fopen(diff_new_filename, "w");
-       rv = fwrite(msg->cm_fields['M'], strlen(msg->cm_fields['M']), 1, fp);
+       rv = fwrite(msg->cm_fields[eMesageText], strlen(msg->cm_fields[eMesageText]), 1, fp);
        fclose(fp);
 
        snprintf(diff_cmd, sizeof diff_cmd,
@@ -183,7 +183,7 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
                fseek(fp, 0L, SEEK_SET);
                diffbuf = malloc(diffbuf_len + 1);
                fread(diffbuf, diffbuf_len, 1, fp);
-               diffbuf[diffbuf_len] = 0;
+               diffbuf[diffbuf_len] = '\0';
                fclose(fp);
        }
 
@@ -212,27 +212,30 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
 
        /* Create a new history message if necessary */
        if (history_msg == NULL) {
+               char *buf;
+               long len;
+
                history_msg = malloc(sizeof(struct CtdlMessage));
                memset(history_msg, 0, sizeof(struct CtdlMessage));
                history_msg->cm_magic = CTDLMESSAGE_MAGIC;
                history_msg->cm_anon_type = MES_NORMAL;
                history_msg->cm_format_type = FMT_RFC822;
-               history_msg->cm_fields['A'] = strdup("Citadel");
-               history_msg->cm_fields['R'] = strdup(CCC->room.QRname);
-               history_msg->cm_fields['E'] = strdup(history_page);
-               history_msg->cm_fields['U'] = strdup(history_page);
-               history_msg->cm_fields['1'] = strdup("1");              /* suppress full text indexing */
+               CM_SetField(history_msg, eAuthor, HKEY("Citadel"));
+               CM_SetField(history_msg, eRecipient, CCC->room.QRname, strlen(CCC->room.QRname));
+               CM_SetField(history_msg, eExclusiveID, history_page, history_page_len);
+               CM_SetField(history_msg, eMsgSubject, history_page, history_page_len);
+               CM_SetField(history_msg, eSuppressIdx, HKEY("1")); /* suppress full text indexing */
                snprintf(boundary, sizeof boundary, "Citadel--Multipart--%04x--%08lx", getpid(), time(NULL));
-               history_msg->cm_fields['M'] = malloc(1024);
-               snprintf(history_msg->cm_fields['M'], 1024,
-                       "Content-type: multipart/mixed; boundary=\"%s\"\n\n"
-                       "This is a Citadel wiki history encoded as multipart MIME.\n"
-                       "Each part is comprised of a diff script representing one change set.\n"
-                       "\n"
-                       "--%s--\n"
-                       ,
-                       boundary, boundary
+               buf = (char*) malloc(1024);
+               len = snprintf(buf, 1024,
+                              "Content-type: multipart/mixed; boundary=\"%s\"\n\n"
+                              "This is a Citadel wiki history encoded as multipart MIME.\n"
+                              "Each part is comprised of a diff script representing one change set.\n"
+                              "\n"
+                              "--%s--\n",
+                              boundary, boundary
                );
+               CM_SetAsField(history_msg, eMesageText, &buf, len);
        }
 
        /* Update the history message (regardless of whether it's new or existing) */
@@ -240,17 +243,14 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
        /* Remove the Message-ID from the old version of the history message.  This will cause a brand
         * new one to be generated, avoiding an uninitentional hit of the loop zapper when we replicate.
         */
-       if (history_msg->cm_fields['I'] != NULL) {
-               free(history_msg->cm_fields['I']);
-               history_msg->cm_fields['I'] = NULL;
-       }
+       CM_FlushField(history_msg, emessageId);
 
        /* Figure out the boundary string.  We do this even when we generated the
         * boundary string in the above code, just to be safe and consistent.
         */
-       strcpy(boundary, "");
+       *boundary = '\0';
 
-       ptr = history_msg->cm_fields['M'];
+       ptr = history_msg->cm_fields[eMesageText];
        do {
                ptr = memreadline(ptr, buf, sizeof buf);
                if (*ptr != 0) {
@@ -279,44 +279,62 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
         * Now look for the first boundary.  That is where we need to insert our fun.
         */
        if (!IsEmptyStr(boundary)) {
-               snprintf(prefixed_boundary, sizeof prefixed_boundary, "--%s", boundary);
-               history_msg->cm_fields['M'] = realloc(history_msg->cm_fields['M'],
-                       strlen(history_msg->cm_fields['M']) + strlen(diffbuf) + 1024
-               );
-               ptr = bmstrcasestr(history_msg->cm_fields['M'], prefixed_boundary);
+               char *MsgText;
+               long MsgTextLen;
+               time_t Now = time(NULL);
+
+               snprintf(prefixed_boundary, sizeof(prefixed_boundary), "--%s", boundary);
+               
+               CM_GetAsField(history_msg, eMesageText, &MsgText, &MsgTextLen);
+
+               ptr = bmstrcasestr(MsgText, prefixed_boundary);
                if (ptr != NULL) {
-                       char *the_rest_of_it = strdup(ptr);
+                       StrBuf *NewMsgText;
                        char uuid[64];
                        char memo[512];
+                       long memolen;
                        char encoded_memo[1024];
+                       
+                       NewMsgText = NewStrBufPlain(NULL, MsgTextLen + diffbuf_len + 1024);
+
                        generate_uuid(uuid);
-                       snprintf(memo, sizeof memo, "%s|%ld|%s|%s", 
-                               uuid,
-                               time(NULL),
-                               CCC->user.fullname,
-                               config.c_nodename
-                       );
-                       CtdlEncodeBase64(encoded_memo, memo, strlen(memo), 0);
-                       sprintf(ptr, "--%s\n"
-                                       "Content-type: text/plain\n"
-                                       "Content-Disposition: inline; filename=\"%s\"\n"
-                                       "Content-Transfer-Encoding: 8bit\n"
-                                       "\n"
-                                       "%s\n"
-                                       "%s"
-                                       ,
-                               boundary,
-                               encoded_memo,
-                               diffbuf,
-                               the_rest_of_it
-                       );
-                       free(the_rest_of_it);
+                       memolen = snprintf(memo, sizeof(memo), "%s|%ld|%s|%s", 
+                                          uuid,
+                                          Now,
+                                          CCC->user.fullname,
+                                          config.c_nodename);
+
+                       memolen = CtdlEncodeBase64(encoded_memo, memo, memolen, 0);
+
+                       StrBufAppendBufPlain(NewMsgText, HKEY("--"), 0);
+                       StrBufAppendBufPlain(NewMsgText, boundary, -1, 0);
+                       StrBufAppendBufPlain(
+                               NewMsgText, 
+                               HKEY("\n"
+                                    "Content-type: text/plain\n"
+                                    "Content-Disposition: inline; filename=\""), 0);
+
+                       StrBufAppendBufPlain(NewMsgText, encoded_memo, memolen, 0);
+
+                       StrBufAppendBufPlain(
+                               NewMsgText, 
+                               HKEY("\"\n"
+                                    "Content-Transfer-Encoding: 8bit\n"
+                                    "\n"), 0);
+
+                       StrBufAppendBufPlain(NewMsgText, diffbuf, diffbuf_len, 0);
+                       StrBufAppendBufPlain(NewMsgText, HKEY("\n"), 0);
+
+                       StrBufAppendBufPlain(NewMsgText, ptr, MsgTextLen - (ptr - MsgText), 0);
+                       free(MsgText);
+                       CM_SetAsFieldSB(history_msg, eMesageText, &NewMsgText); 
                }
-
-               history_msg->cm_fields['T'] = realloc(history_msg->cm_fields['T'], 32);
-               if (history_msg->cm_fields['T'] != NULL) {
-                       snprintf(history_msg->cm_fields['T'], 32, "%ld", time(NULL));
+               else
+               {
+                       CM_SetAsField(history_msg, eMesageText, &MsgText, MsgTextLen); 
                }
+
+               CM_SetFieldLONG(history_msg, eTimestamp, Now);
        
                CtdlSubmitMsg(history_msg, NULL, "", 0);
        }
@@ -325,7 +343,7 @@ int wiki_upload_beforesave(struct CtdlMessage *msg) {
        }
 
        free(diffbuf);
-       free(history_msg);
+       CM_Free(history_msg);
        return(0);
 }
 
@@ -377,8 +395,8 @@ void wiki_history(char *pagename) {
                msg = NULL;
        }
 
-       if ((msg != NULL) && (msg->cm_fields['M'] == NULL)) {
-               CtdlFreeMessage(msg);
+       if ((msg != NULL) && CM_IsEmpty(msg, eMesageText)) {
+               CM_Free(msg);
                msg = NULL;
        }
 
@@ -389,10 +407,10 @@ void wiki_history(char *pagename) {
 
        
        cprintf("%d Revision history for '%s'\n", LISTING_FOLLOWS, pagename);
-       mime_parser(msg->cm_fields['M'], NULL, *wiki_history_callback, NULL, NULL, NULL, 0);
+       mime_parser(msg->cm_fields[eMesageText], NULL, *wiki_history_callback, NULL, NULL, NULL, 0);
        cprintf("000\n");
 
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        return;
 }
 
@@ -468,11 +486,11 @@ void wiki_rev_callback(char *name, char *filename, char *partnum, char *disp,
  */
 void wiki_rev(char *pagename, char *rev, char *operation)
 {
+       struct CitContext *CCC = CC;
        int r;
        char history_page_name[270];
        long msgnum;
        char temp[PATH_MAX];
-       char timestamp[64];
        struct CtdlMessage *msg;
        FILE *fp;
        struct HistoryEraserCallBackData hecbd;
@@ -501,7 +519,7 @@ void wiki_rev(char *pagename, char *rev, char *operation)
        /* Begin by fetching the current version of the page.  We're going to patch
         * backwards through the diffs until we get the one we want.
         */
-       msgnum = CtdlLocateMessageByEuid(pagename, &CC->room);
+       msgnum = CtdlLocateMessageByEuid(pagename, &CCC->room);
        if (msgnum > 0L) {
                msg = CtdlFetchMessage(msgnum, 1);
        }
@@ -509,8 +527,8 @@ void wiki_rev(char *pagename, char *rev, char *operation)
                msg = NULL;
        }
 
-       if ((msg != NULL) && (msg->cm_fields['M'] == NULL)) {
-               CtdlFreeMessage(msg);
+       if ((msg != NULL) && CM_IsEmpty(msg, eMesageText)) {
+               CM_Free(msg);
                msg = NULL;
        }
 
@@ -524,18 +542,18 @@ void wiki_rev(char *pagename, char *rev, char *operation)
        CtdlMakeTempFileName(temp, sizeof temp);
        fp = fopen(temp, "w");
        if (fp != NULL) {
-               r = fwrite(msg->cm_fields['M'], strlen(msg->cm_fields['M']), 1, fp);
+               r = fwrite(msg->cm_fields[eMesageText], strlen(msg->cm_fields[eMesageText]), 1, fp);
                fclose(fp);
        }
        else {
                syslog(LOG_ALERT, "Cannot open %s: %s\n", temp, strerror(errno));
        }
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        /* Get the revision history */
 
        snprintf(history_page_name, sizeof history_page_name, "%s_HISTORY_", pagename);
-       msgnum = CtdlLocateMessageByEuid(history_page_name, &CC->room);
+       msgnum = CtdlLocateMessageByEuid(history_page_name, &CCC->room);
        if (msgnum > 0L) {
                msg = CtdlFetchMessage(msgnum, 1);
        }
@@ -543,8 +561,8 @@ void wiki_rev(char *pagename, char *rev, char *operation)
                msg = NULL;
        }
 
-       if ((msg != NULL) && (msg->cm_fields['M'] == NULL)) {
-               CtdlFreeMessage(msg);
+       if ((msg != NULL) && CM_IsEmpty(msg, eMesageText)) {
+               CM_Free(msg);
                msg = NULL;
        }
 
@@ -562,8 +580,8 @@ void wiki_rev(char *pagename, char *rev, char *operation)
        hecbd.stop_when = rev;
        striplt(hecbd.stop_when);
 
-       mime_parser(msg->cm_fields['M'], NULL, *wiki_rev_callback, NULL, NULL, (void *)&hecbd, 0);
-       CtdlFreeMessage(msg);
+       mime_parser(msg->cm_fields[eMesageText], NULL, *wiki_rev_callback, NULL, NULL, (void *)&hecbd, 0);
+       CM_Free(msg);
 
        /* Were we successful? */
        if (hecbd.done == 0) {
@@ -582,20 +600,22 @@ void wiki_rev(char *pagename, char *rev, char *operation)
                msg->cm_format_type = FMT_RFC822;
                fp = fopen(temp, "r");
                if (fp) {
+                       char *msgbuf;
                        fseek(fp, 0L, SEEK_END);
                        len = ftell(fp);
                        fseek(fp, 0L, SEEK_SET);
-                       msg->cm_fields['M'] = malloc(len + 1);
-                       rv = fread(msg->cm_fields['M'], len, 1, fp);
+                       msgbuf = malloc(len + 1);
+                       rv = fread(msgbuf, len, 1, fp);
                        syslog(LOG_DEBUG, "did %d blocks of %ld bytes\n", rv, len);
-                       msg->cm_fields['M'][len] = 0;
+                       msgbuf[len] = '\0';
+                       CM_SetAsField(msg, eMesageText, &msgbuf, len);
                        fclose(fp);
                }
                if (len <= 0) {
                        msgnum = (-1L);
                }
                else if (!strcasecmp(operation, "fetch")) {
-                       msg->cm_fields['A'] = strdup("Citadel");
+                       CM_SetField(msg, eAuthor, HKEY("Citadel"));
                        CtdlCreateRoom(wwm, 5, "", 0, 1, 1, VIEW_BBS);  /* Not an error if already exists */
                        msgnum = CtdlSubmitMsg(msg, NULL, wwm, 0);      /* Store the revision here */
 
@@ -605,33 +625,32 @@ void wiki_rev(char *pagename, char *rev, char *operation)
                         * but only if the client fetches the message we just generated immediately
                         * without first trying to perform other fetch operations.
                         */
-                       if (CC->cached_msglist != NULL) {
-                               free(CC->cached_msglist);
-                               CC->cached_msglist = NULL;
-                               CC->cached_num_msgs = 0;
+                       if (CCC->cached_msglist != NULL) {
+                               free(CCC->cached_msglist);
+                               CCC->cached_msglist = NULL;
+                               CCC->cached_num_msgs = 0;
                        }
-                       CC->cached_msglist = malloc(sizeof(long));
-                       if (CC->cached_msglist != NULL) {
-                               CC->cached_num_msgs = 1;
-                               CC->cached_msglist[0] = msgnum;
+                       CCC->cached_msglist = malloc(sizeof(long));
+                       if (CCC->cached_msglist != NULL) {
+                               CCC->cached_num_msgs = 1;
+                               CCC->cached_msglist[0] = msgnum;
                        }
 
                }
                else if (!strcasecmp(operation, "revert")) {
-                       snprintf(timestamp, sizeof timestamp, "%ld", time(NULL));
-                       msg->cm_fields['T'] = strdup(timestamp);
-                       msg->cm_fields['A'] = strdup(CC->user.fullname);
-                       msg->cm_fields['F'] = strdup(CC->cs_inet_email);
-                       msg->cm_fields['O'] = strdup(CC->room.QRname);
-                       msg->cm_fields['N'] = strdup(NODENAME);
-                       msg->cm_fields['E'] = strdup(pagename);
+                       CM_SetFieldLONG(msg, eTimestamp, time(NULL));
+                       CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
+                       CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email));
+                       CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
+                       CM_SetField(msg, eNodeName, NODENAME, strlen(NODENAME));
+                       CM_SetField(msg, eExclusiveID, pagename, strlen(pagename));
                        msgnum = CtdlSubmitMsg(msg, NULL, "", 0);       /* Replace the current revision */
                }
                else {
                        /* Theoretically it is impossible to get here, but throw an error anyway */
                        msgnum = (-1L);
                }
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
                if (msgnum >= 0L) {
                        cprintf("%d %ld\n", CIT_OK, msgnum);            /* Give the client a msgnum */
                }
index d4e69316ab80a8f8c7157f7e20983146ed2c50f1..ca8a95949d8d95b10dc7e8d679787ab072a600ac 100644 (file)
@@ -238,12 +238,12 @@ void xmpp_fetch_mortuary_backend(long msgnum, void *userdata) {
        /* now add anyone we find into the hashlist */
 
        /* skip past the headers */
-       ptr = strstr(msg->cm_fields['M'], "\n\n");
+       ptr = strstr(msg->cm_fields[eMesageText], "\n\n");
        if (ptr != NULL) {
                ptr += 2;
        }
        else {
-               ptr = strstr(msg->cm_fields['M'], "\n\r\n");
+               ptr = strstr(msg->cm_fields[eMesageText], "\n\r\n");
                if (ptr != NULL) {
                        ptr += 3;
                }
@@ -259,7 +259,7 @@ void xmpp_fetch_mortuary_backend(long msgnum, void *userdata) {
                }
        }
 
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
index cb94c8f8984e466315348c4ff0dd1d5d305f5951..03ef35df6158d99a1d5151cc17b305a61832018a 100644 (file)
@@ -65,7 +65,6 @@
 
 #include "ctdl_module.h"
 
-long config_msgnum;
 struct addresses_to_be_filed *atbf = NULL;
 
 /* This temp file holds the queue of operations for AdjRefCount() */
@@ -116,7 +115,54 @@ char *msgkeys[] = {
        NULL    /* Z */
 };
 
-void CtdlMsgSetCM_Fields(struct CtdlMessage *Msg, const char which, const char *buf, long length)
+eMsgField FieldOrder[]  = {
+/* Important fields */
+       emessageId   ,
+       eMessagePath ,
+       eTimestamp   ,
+       eAuthor      ,
+       erFc822Addr  ,
+       eOriginalRoom,
+       eNodeName    ,
+       eHumanNode   ,
+       eRecipient   ,
+       eDestination ,
+/* Semi-important fields */
+       eBig_message ,
+       eRemoteRoom  ,
+       eExclusiveID ,
+       eWeferences  ,
+       eJournal     ,
+/* G is not used yet, may become virus signature*/
+       eReplyTo     ,
+       eListID      ,
+/* Q is not used yet */
+       eSpecialField,
+       eenVelopeTo  ,
+/* X is not used yet */
+/* Z is not used yet */
+       eCarbonCopY  ,
+       eMsgSubject  ,
+/* internal only */
+       eErrorMsg    ,
+       eSuppressIdx ,
+       eExtnotify   ,
+/* Message text (MUST be last) */
+       eMesageText 
+/* Not saved to disk: 
+       eVltMsgNum
+*/
+};
+
+static const long NDiskFields = sizeof(FieldOrder) / sizeof(eMsgField);
+
+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]);
@@ -125,197 +171,182 @@ void CtdlMsgSetCM_Fields(struct CtdlMessage *Msg, const char which, const char *
        Msg->cm_fields[which][length] = '\0';
 }
 
-/*
- * This function is self explanatory.
- * (What can I say, I'm in a weird mood today...)
- */
-void remove_any_whitespace_to_the_left_or_right_of_at_symbol(char *name)
+void CM_SetFieldLONG(struct CtdlMessage *Msg, eMsgField which, long lvalue)
 {
-       int i;
+       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;
 
-       for (i = 0; i < strlen(name); ++i) {
-               if (name[i] == '@') {
-                       while (isspace(name[i - 1]) && i > 0) {
-                               strcpy(&name[i - 1], &name[i]);
-                               --i;
-                       }
-                       while (isspace(name[i + 1])) {
-                               strcpy(&name[i + 1], &name[i + 2]);
-                       }
-               }
-       }
+       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;
+}
 
-/*
- * Aliasing for network mail.
- * (Error messages have been commented out, because this is a server.)
- */
-int alias(char *name)
-{                              /* process alias and routing info for mail */
-       struct CitContext *CCC = CC;
-       FILE *fp;
-       int a, i;
-       char aaa[SIZ], bbb[SIZ];
-       char *ignetcfg = NULL;
-       char *ignetmap = NULL;
-       int at = 0;
-       char node[64];
-       char testnode[64];
-       char buf[SIZ];
+void CM_CopyField(struct CtdlMessage *Msg, eMsgField WhichToPutTo, eMsgField WhichtToCopy)
+{
+       long len;
+       if (Msg->cm_fields[WhichToPutTo] != NULL)
+               free (Msg->cm_fields[WhichToPutTo]);
 
-       char original_name[256];
-       safestrncpy(original_name, name, sizeof original_name);
+       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;
+}
 
-       striplt(name);
-       remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
-       stripallbut(name, '<', '>');
 
-       fp = fopen(file_mail_aliases, "r");
-       if (fp == NULL) {
-               fp = fopen("/dev/null", "r");
-       }
-       if (fp == NULL) {
-               return (MES_ERROR);
-       }
-       strcpy(aaa, "");
-       strcpy(bbb, "");
-       while (fgets(aaa, sizeof aaa, fp) != NULL) {
-               while (isspace(name[0]))
-                       strcpy(name, &name[1]);
-               aaa[strlen(aaa) - 1] = 0;
-               strcpy(bbb, "");
-               for (a = 0; a < strlen(aaa); ++a) {
-                       if (aaa[a] == ',') {
-                               strcpy(bbb, &aaa[a + 1]);
-                               aaa[a] = 0;
-                       }
-               }
-               if (!strcasecmp(name, aaa))
-                       strcpy(name, bbb);
-       }
-       fclose(fp);
+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;
 
-       /* Hit the Global Address Book */
-       if (CtdlDirectoryLookup(aaa, name, sizeof aaa) == 0) {
-               strcpy(name, aaa);
-       }
+               oldmsgsize = strlen(Msg->cm_fields[which]) + 1;
+               newmsgsize = length + oldmsgsize;
 
-       if (strcasecmp(original_name, name)) {
-               MSG_syslog(LOG_INFO, "%s is being forwarded to %s\n", original_name, name);
+               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;
        }
-
-       /* Change "user @ xxx" to "user" if xxx is an alias for this host */
-       for (a=0; a<strlen(name); ++a) {
-               if (name[a] == '@') {
-                       if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) {
-                               name[a] = 0;
-                               MSG_syslog(LOG_INFO, "Changed to <%s>\n", name);
-                       }
-               }
+       else {
+               Msg->cm_fields[which] = malloc(length + 1);
+               memcpy(Msg->cm_fields[which], buf, length);
+               Msg->cm_fields[which][length] = '\0';
        }
+}
 
-       /* determine local or remote type, see citadel.h */
-       at = haschar(name, '@');
-       if (at == 0) return(MES_LOCAL);         /* no @'s - local address */
-       if (at > 1) return(MES_ERROR);          /* >1 @'s - invalid address */
-       remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
+void CM_SetAsField(struct CtdlMessage *Msg, eMsgField which, char **buf, long length)
+{
+       if (Msg->cm_fields[which] != NULL)
+               free (Msg->cm_fields[which]);
 
-       /* figure out the delivery mode */
-       extract_token(node, name, 1, '@', sizeof node);
+       Msg->cm_fields[which] = *buf;
+       *buf = NULL;
+}
 
-       /* If there are one or more dots in the nodename, we assume that it
-        * is an FQDN and will attempt SMTP delivery to the Internet.
-        */
-       if (haschar(node, '.') > 0) {
-               return(MES_INTERNET);
-       }
+void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf)
+{
+       if (Msg->cm_fields[which] != NULL)
+               free (Msg->cm_fields[which]);
 
-       /* Otherwise we look in the IGnet maps for a valid Citadel node.
-        * Try directly-connected nodes first...
-        */
-       ignetcfg = CtdlGetSysConfig(IGNETCFG);
-       for (i=0; i<num_tokens(ignetcfg, '\n'); ++i) {
-               extract_token(buf, ignetcfg, i, '\n', sizeof buf);
-               extract_token(testnode, buf, 0, '|', sizeof testnode);
-               if (!strcasecmp(node, testnode)) {
-                       free(ignetcfg);
-                       return(MES_IGNET);
-               }
-       }
-       free(ignetcfg);
+       Msg->cm_fields[which] = SmashStrBuf(buf);
+}
 
-       /*
-        * Then try nodes that are two or more hops away.
-        */
-       ignetmap = CtdlGetSysConfig(IGNETMAP);
-       for (i=0; i<num_tokens(ignetmap, '\n'); ++i) {
-               extract_token(buf, ignetmap, i, '\n', sizeof buf);
-               extract_token(testnode, buf, 0, '|', sizeof testnode);
-               if (!strcasecmp(node, testnode)) {
-                       free(ignetmap);
-                       return(MES_IGNET);
-               }
+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;
        }
-       free(ignetmap);
-
-       /* If we get to this point it's an invalid node name */
-       return (MES_ERROR);
 }
 
-
 /*
- * Back end for the MSGS command: output message number only.
+ * 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.
  */
-void simple_listing(long msgnum, void *userdata)
-{
-       cprintf("%ld\n", msgnum);
+int CM_IsValidMsg(struct CtdlMessage *msg) {
+       if (msg == NULL)
+               return 0;
+       if ((msg->cm_magic) != CTDLMESSAGE_MAGIC) {
+               struct CitContext *CCC = CC;
+               MSGM_syslog(LOG_WARNING, "CM_IsValidMsg() -- self-check failed\n");
+               return 0;
+       }
+       return 1;
 }
 
+void CM_FreeContents(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 */
+}
 /*
- * Back end for the MSGS command: output header summary.
+ * 'Destructor' for struct CtdlMessage
  */
-void headers_listing(long msgnum, void *userdata)
+void CM_Free(struct CtdlMessage *msg)
 {
-       struct CtdlMessage *msg;
-
-       msg = CtdlFetchMessage(msgnum, 0);
-       if (msg == NULL) {
-               cprintf("%ld|0|||||\n", msgnum);
+       if (CM_IsValidMsg(msg) == 0) 
+       {
+               if (msg != NULL) free (msg);
                return;
        }
+       CM_FreeContents(msg);
+       free(msg);
+}
 
-       cprintf("%ld|%s|%s|%s|%s|%s|\n",
-               msgnum,
-               (msg->cm_fields['T'] ? msg->cm_fields['T'] : "0"),
-               (msg->cm_fields['A'] ? msg->cm_fields['A'] : ""),
-               (msg->cm_fields['N'] ? msg->cm_fields['N'] : ""),
-               (msg->cm_fields['F'] ? msg->cm_fields['F'] : ""),
-               (msg->cm_fields['U'] ? msg->cm_fields['U'] : "")
-       );
-       CtdlFreeMessage(msg);
+int CM_DupField(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;
 }
 
-/*
- * Back end for the MSGS command: output EUID header.
- */
-void headers_euid(long msgnum, void *userdata)
+struct CtdlMessage * CM_Duplicate(struct CtdlMessage *OrgMsg)
 {
-       struct CtdlMessage *msg;
+       int i;
+       struct CtdlMessage *NewMsg;
 
-       msg = CtdlFetchMessage(msgnum, 0);
-       if (msg == NULL) {
-               cprintf("%ld||\n", msgnum);
-               return;
+       if (CM_IsValidMsg(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 (!CM_DupField(i, OrgMsg, NewMsg))
+                       {
+                               CM_Free(NewMsg);
+                               return NULL;
+                       }
+               }
        }
 
-       cprintf("%ld|%s|%s\n", 
-               msgnum, 
-               (msg->cm_fields['E'] ? msg->cm_fields['E'] : ""),
-               (msg->cm_fields['T'] ? msg->cm_fields['T'] : "0"));
-       CtdlFreeMessage(msg);
+       return NewMsg;
 }
 
 
@@ -715,7 +746,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
                                        if (CtdlMsgCmp(msg, compare)) {
                                                msglist[a] = 0L;
                                        }
-                                       CtdlFreeMessage(msg);
+                                       CM_Free(msg);
                                }
                        }
                }
@@ -830,143 +861,6 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
 
 
 
-/*
- * cmd_msgs()  -  get list of message #'s in this room
- *             implements the MSGS server command using CtdlForEachMessage()
- */
-void cmd_msgs(char *cmdbuf)
-{
-       int mode = 0;
-       char which[16];
-       char buf[256];
-       char tfield[256];
-       char tvalue[256];
-       int cm_ref = 0;
-       int i;
-       int with_template = 0;
-       struct CtdlMessage *template = NULL;
-       char search_string[1024];
-       ForEachMsgCallback CallBack;
-
-       if (CtdlAccessCheck(ac_logged_in_or_guest)) return;
-
-       extract_token(which, cmdbuf, 0, '|', sizeof which);
-       cm_ref = extract_int(cmdbuf, 1);
-       extract_token(search_string, cmdbuf, 1, '|', sizeof search_string);
-       with_template = extract_int(cmdbuf, 2);
-       switch (extract_int(cmdbuf, 3))
-       {
-       default:
-       case MSG_HDRS_BRIEF:
-               CallBack = simple_listing;
-               break;
-       case MSG_HDRS_ALL:
-               CallBack = headers_listing;
-               break;
-       case MSG_HDRS_EUID:
-               CallBack = headers_euid;
-               break;
-       }
-
-       strcat(which, "   ");
-       if (!strncasecmp(which, "OLD", 3))
-               mode = MSGS_OLD;
-       else if (!strncasecmp(which, "NEW", 3))
-               mode = MSGS_NEW;
-       else if (!strncasecmp(which, "FIRST", 5))
-               mode = MSGS_FIRST;
-       else if (!strncasecmp(which, "LAST", 4))
-               mode = MSGS_LAST;
-       else if (!strncasecmp(which, "GT", 2))
-               mode = MSGS_GT;
-       else if (!strncasecmp(which, "LT", 2))
-               mode = MSGS_LT;
-       else if (!strncasecmp(which, "SEARCH", 6))
-               mode = MSGS_SEARCH;
-       else
-               mode = MSGS_ALL;
-
-       if ( (mode == MSGS_SEARCH) && (!config.c_enable_fulltext) ) {
-               cprintf("%d Full text index is not enabled on this server.\n",
-                       ERROR + CMD_NOT_SUPPORTED);
-               return;
-       }
-
-       if (with_template) {
-               unbuffer_output();
-               cprintf("%d Send template then receive message list\n",
-                       START_CHAT_MODE);
-               template = (struct CtdlMessage *)
-                       malloc(sizeof(struct CtdlMessage));
-               memset(template, 0, sizeof(struct CtdlMessage));
-               template->cm_magic = CTDLMESSAGE_MAGIC;
-               template->cm_anon_type = MES_NORMAL;
-
-               while(client_getln(buf, sizeof buf) >= 0 && strcmp(buf,"000")) {
-                       extract_token(tfield, buf, 0, '|', sizeof tfield);
-                       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);
-                               }
-                       }
-               }
-               buffer_output();
-       }
-       else {
-               cprintf("%d  \n", LISTING_FOLLOWS);
-       }
-
-       CtdlForEachMessage(mode,
-                          ( (mode == MSGS_SEARCH) ? 0 : cm_ref ),
-                          ( (mode == MSGS_SEARCH) ? search_string : NULL ),
-                          NULL,
-                          template,
-                          CallBack,
-                          NULL);
-       if (template != NULL) CtdlFreeMessage(template);
-       cprintf("000\n");
-}
-
-
-
-
-/* 
- * help_subst()  -  support routine for help file viewer
- */
-void help_subst(char *strbuf, char *source, char *dest)
-{
-       char workbuf[SIZ];
-       int p;
-
-       while (p = pattern2(strbuf, source), (p >= 0)) {
-               strcpy(workbuf, &strbuf[p + strlen(source)]);
-               strcpy(&strbuf[p], dest);
-               strcat(strbuf, workbuf);
-       }
-}
-
-
-void do_help_subst(char *buffer)
-{
-       char buf2[16];
-
-       help_subst(buffer, "^nodename", config.c_nodename);
-       help_subst(buffer, "^humannode", config.c_humannode);
-       help_subst(buffer, "^fqdn", config.c_fqdn);
-       help_subst(buffer, "^username", CC->user.fullname);
-       snprintf(buf2, sizeof buf2, "%ld", CC->user.usernum);
-       help_subst(buffer, "^usernum", buf2);
-       help_subst(buffer, "^sysadm", config.c_sysadm);
-       help_subst(buffer, "^variantname", CITADEL);
-       snprintf(buf2, sizeof buf2, "%d", config.c_maxsessions);
-       help_subst(buffer, "^maxsessions", buf2);
-       help_subst(buffer, "^bbsdir", ctdl_message_dir);
-}
-
-
-
 /*
  * memfmout()  -  Citadel text formatter and paginator.
  *          Although the original purpose of this routine was to format
@@ -1243,13 +1137,15 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body)
         * 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'));
 
@@ -1260,21 +1156,20 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body)
         * so go ahead and fetch that.  Failing that, just set a dummy
         * body so other code doesn't barf.
         */
-       if ( (ret->cm_fields['M'] == NULL) && (with_body) ) {
+       if ( (CM_IsEmpty(ret, eMesageText)) && (with_body) ) {
                dmsgtext = cdb_fetch(CDB_BIGMSGS, &msgnum, sizeof(long));
                if (dmsgtext != NULL) {
-                       ret->cm_fields['M'] = dmsgtext->ptr;
-                       dmsgtext->ptr = NULL;
+                       CM_SetAsField(ret, eMesageText, &dmsgtext->ptr, dmsgtext->len);
                        cdb_free(dmsgtext);
                }
        }
-       if (ret->cm_fields['M'] == NULL) {
-               ret->cm_fields['M'] = 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) */
        if (PerformMessageHooks(ret, EVT_BEFOREREAD) > 0) {
-               CtdlFreeMessage(ret);
+               CM_Free(ret);
                return NULL;
        }
 
@@ -1282,89 +1177,6 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body)
 }
 
 
-/*
- * 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
@@ -1687,20 +1499,6 @@ int check_cached_msglist(long msgnum) {
 }
 
 
-/* 
- * Determine whether the currently logged in session has permission to read
- * messages in the current room.
- */
-int CtdlDoIHavePermissionToReadMessagesInThisRoom(void) {
-       if (    (!(CC->logged_in))
-               && (!(CC->internal_pgm))
-               && (!config.c_guest_logins)
-       ) {
-               return(om_not_logged_in);
-       }
-       return(om_ok);
-}
-
 
 /*
  * Get a message off disk.  (returns om_* values found in msgbase.h)
@@ -1787,7 +1585,7 @@ int CtdlOutputMsg(long msg_num,           /* message number (local) to fetch */
        if (section) if (!IsEmptyStr(section)) if (strcmp(section, "0")) {
                memset(&encap, 0, sizeof encap);
                safestrncpy(encap.desired_section, section, sizeof encap.desired_section);
-               mime_parser(TheMessage->cm_fields['M'],
+               mime_parser(TheMessage->cm_fields[eMesageText],
                        NULL,
                        *extract_encapsulated_message,
                        NULL, NULL, (void *)&encap, 0
@@ -1795,15 +1593,15 @@ int CtdlOutputMsg(long msg_num,         /* message number (local) to fetch */
 
                if ((Author != NULL) && (*Author == NULL))
                {
-                       *Author = TheMessage->cm_fields['A'];
-                       TheMessage->cm_fields['A'] = NULL;
+                       *Author = TheMessage->cm_fields[eAuthor];
+                       TheMessage->cm_fields[eAuthor] = NULL;
                }
                if ((Address != NULL) && (*Address == NULL))
                {       
-                       *Address = TheMessage->cm_fields['F'];
-                       TheMessage->cm_fields['F'] = NULL;
+                       *Address = TheMessage->cm_fields[erFc822Addr];
+                       TheMessage->cm_fields[erFc822Addr] = NULL;
                }
-               CtdlFreeMessage(TheMessage);
+               CM_Free(TheMessage);
                TheMessage = NULL;
 
                if (encap.msg) {
@@ -1816,7 +1614,6 @@ int CtdlOutputMsg(long msg_num,           /* message number (local) to fetch */
                         * encapsulated message instead of the top-level
                         * message.  Isn't that neat?
                         */
-
                }
                else {
                        if (do_proto) {
@@ -1835,186 +1632,35 @@ int CtdlOutputMsg(long msg_num,                /* message number (local) to fetch */
                retcode = CtdlOutputPreLoadedMsg(TheMessage, mode, headers_only, do_proto, crlf, flags);
        if ((Author != NULL) && (*Author == NULL))
        {
-               *Author = TheMessage->cm_fields['A'];
-               TheMessage->cm_fields['A'] = NULL;
+               *Author = TheMessage->cm_fields[eAuthor];
+               TheMessage->cm_fields[eAuthor] = NULL;
        }
        if ((Address != NULL) && (*Address == NULL))
        {       
-               *Address = TheMessage->cm_fields['F'];
-               TheMessage->cm_fields['F'] = NULL;
+               *Address = TheMessage->cm_fields[erFc822Addr];
+               TheMessage->cm_fields[erFc822Addr] = NULL;
        }
 
-       CtdlFreeMessage(TheMessage);
+       CM_Free(TheMessage);
 
        return(retcode);
 }
 
 
-char *qp_encode_email_addrs(char *source)
-{
-       struct CitContext *CCC = CC;
-       char *user, *node, *name;
-       const char headerStr[] = "=?UTF-8?Q?";
-       char *Encoded;
-       char *EncodedName;
-       char *nPtr;
-       int need_to_encode = 0;
-       long SourceLen;
-       long EncodedMaxLen;
-       long nColons = 0;
-       long *AddrPtr;
-       long *AddrUtf8;
-       long nAddrPtrMax = 50;
-       long nmax;
-       int InQuotes = 0;
-       int i, n;
-
-       if (source == NULL) return source;
-       if (IsEmptyStr(source)) return source;
-       if (MessageDebugEnabled != 0) cit_backtrace();
-       MSG_syslog(LOG_DEBUG, "qp_encode_email_addrs: [%s]\n", source);
-
-       AddrPtr = malloc (sizeof (long) * nAddrPtrMax);
-       AddrUtf8 = malloc (sizeof (long) * nAddrPtrMax);
-       memset(AddrUtf8, 0, sizeof (long) * nAddrPtrMax);
-       *AddrPtr = 0;
-       i = 0;
-       while (!IsEmptyStr (&source[i])) {
-               if (nColons >= nAddrPtrMax){
-                       long *ptr;
-
-                       ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2);
-                       memcpy (ptr, AddrPtr, sizeof (long) * nAddrPtrMax);
-                       free (AddrPtr), AddrPtr = ptr;
-
-                       ptr = (long *) malloc(sizeof (long) * nAddrPtrMax * 2);
-                       memset(&ptr[nAddrPtrMax], 0, 
-                              sizeof (long) * nAddrPtrMax);
-
-                       memcpy (ptr, AddrUtf8, sizeof (long) * nAddrPtrMax);
-                       free (AddrUtf8), AddrUtf8 = ptr;
-                       nAddrPtrMax *= 2;                               
-               }
-               if (((unsigned char) source[i] < 32) || 
-                   ((unsigned char) source[i] > 126)) {
-                       need_to_encode = 1;
-                       AddrUtf8[nColons] = 1;
-               }
-               if (source[i] == '"')
-                       InQuotes = !InQuotes;
-               if (!InQuotes && source[i] == ',') {
-                       AddrPtr[nColons] = i;
-                       nColons++;
-               }
-               i++;
-       }
-       if (need_to_encode == 0) {
-               free(AddrPtr);
-               free(AddrUtf8);
-               return source;
-       }
-
-       SourceLen = i;
-       EncodedMaxLen = nColons * (sizeof(headerStr) + 3) + SourceLen * 3;
-       Encoded = (char*) malloc (EncodedMaxLen);
-
-       for (i = 0; i < nColons; i++)
-               source[AddrPtr[i]++] = '\0';
-       /* TODO: if libidn, this might get larger*/
-       user = malloc(SourceLen + 1);
-       node = malloc(SourceLen + 1);
-       name = malloc(SourceLen + 1);
-
-       nPtr = Encoded;
-       *nPtr = '\0';
-       for (i = 0; i < nColons && nPtr != NULL; i++) {
-               nmax = EncodedMaxLen - (nPtr - Encoded);
-               if (AddrUtf8[i]) {
-                       process_rfc822_addr(&source[AddrPtr[i]], 
-                                           user,
-                                           node,
-                                           name);
-                       /* TODO: libIDN here ! */
-                       if (IsEmptyStr(name)) {
-                               n = snprintf(nPtr, nmax, 
-                                            (i==0)?"%s@%s" : ",%s@%s",
-                                            user, node);
-                       }
-                       else {
-                               EncodedName = rfc2047encode(name, strlen(name));                        
-                               n = snprintf(nPtr, nmax, 
-                                            (i==0)?"%s <%s@%s>" : ",%s <%s@%s>",
-                                            EncodedName, user, node);
-                               free(EncodedName);
-                       }
-               }
-               else { 
-                       n = snprintf(nPtr, nmax, 
-                                    (i==0)?"%s" : ",%s",
-                                    &source[AddrPtr[i]]);
-               }
-               if (n > 0 )
-                       nPtr += n;
-               else { 
-                       char *ptr, *nnPtr;
-                       ptr = (char*) malloc(EncodedMaxLen * 2);
-                       memcpy(ptr, Encoded, EncodedMaxLen);
-                       nnPtr = ptr + (nPtr - Encoded), nPtr = nnPtr;
-                       free(Encoded), Encoded = ptr;
-                       EncodedMaxLen *= 2;
-                       i--; /* do it once more with properly lengthened buffer */
-               }
-       }
-       for (i = 0; i < nColons; i++)
-               source[--AddrPtr[i]] = ',';
-
-       free(user);
-       free(node);
-       free(name);
-       free(AddrUtf8);
-       free(AddrPtr);
-       return Encoded;
-}
-
-
-/* If the last item in a list of recipients was truncated to a partial address,
- * remove it completely in order to avoid choking libSieve
- */
-void sanitize_truncated_recipient(char *str)
-{
-       if (!str) return;
-       if (num_tokens(str, ',') < 2) return;
-
-       int len = strlen(str);
-       if (len < 900) return;
-       if (len > 998) str[998] = 0;
-
-       char *cptr = strrchr(str, ',');
-       if (!cptr) return;
-
-       char *lptr = strchr(cptr, '<');
-       char *rptr = strchr(cptr, '>');
-
-       if ( (lptr) && (rptr) && (rptr > lptr) ) return;
-
-       *cptr = 0;
-}
-
 
 void OutputCtdlMsgHeaders(
        struct CtdlMessage *TheMessage,
        int do_proto)           /* do Citadel protocol responses? */
 {
-       char allkeys[30];
-       int i, k, n;
+       int i;
        int suppress_f = 0;
        char buf[SIZ];
        char display_name[256];
 
        /* begin header processing loop for Citadel message format */
        safestrncpy(display_name, "<unknown>", sizeof display_name);
-       if (TheMessage->cm_fields['A']) {
-               strcpy(buf, TheMessage->cm_fields['A']);
+       if (!CM_IsEmpty(TheMessage, eAuthor)) {
+               strcpy(buf, TheMessage->cm_fields[eAuthor]);
                if (TheMessage->cm_anon_type == MES_ANONONLY) {
                        safestrncpy(display_name, "****", sizeof display_name);
                }
@@ -2038,35 +1684,37 @@ void OutputCtdlMsgHeaders(
         * local Citadel network.
         */
        suppress_f = 0;
-       if (TheMessage->cm_fields['N'] != NULL)
-               if (!IsEmptyStr(TheMessage->cm_fields['N']))
-                       if (haschar(TheMessage->cm_fields['N'], '.') == 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. */
-       n = safestrncpy(allkeys, FORDER, sizeof allkeys);
-       for (i=0; i<n; ++i) {
-               k = (int) allkeys[i];
-               if (k != 'M') {
-                       if ( (TheMessage->cm_fields[k] != NULL)
-                            && (msgkeys[k] != NULL) ) {
-                               if ((k == 'V') || (k == 'R') || (k == 'Y')) {
-                                       sanitize_truncated_recipient(TheMessage->cm_fields[k]);
+       for (i=0; i< NDiskFields; ++i) {
+               eMsgField Field;
+               Field = FieldOrder[i];
+               if (Field != eMesageText) {
+                       if ( (!CM_IsEmpty(TheMessage, Field))
+                            && (msgkeys[Field] != NULL) ) {
+                               if ((Field == eenVelopeTo) ||
+                                   (Field == eRecipient) ||
+                                   (Field == eCarbonCopY)) {
+                                       sanitize_truncated_recipient(TheMessage->cm_fields[Field]);
                                }
-                               if (k == 'A') {
+                               if (Field == eAuthor) {
                                        if (do_proto) cprintf("%s=%s\n",
-                                                             msgkeys[k],
+                                                             msgkeys[Field],
                                                              display_name);
                                }
-                               else if ((k == 'F') && (suppress_f)) {
+                               else if ((Field == erFc822Addr) && (suppress_f)) {
                                        /* do nothing */
                                }
                                /* Masquerade display name if needed */
                                else {
                                        if (do_proto) cprintf("%s=%s\n",
-                                                             msgkeys[k],
-                                                             TheMessage->cm_fields[k]
+                                                             msgkeys[Field],
+                                                             TheMessage->cm_fields[Field]
                                                );
                                }
                        }
@@ -2097,7 +1745,7 @@ void OutputRFC822MsgHeaders(
                if (TheMessage->cm_fields[i]) {
                        mptr = mpptr = TheMessage->cm_fields[i];
                                
-                       if (i == 'A') {
+                       if (i == eAuthor) {
                                safestrncpy(luser, mptr, sizeof_luser);
                                safestrncpy(suser, mptr, sizeof_suser);
                        }
@@ -2111,7 +1759,7 @@ void OutputRFC822MsgHeaders(
                        else if (i == 'P') {
                                cprintf("Return-Path: %s%s", mptr, nl);
                        }
-                       else if (i == 'L') {
+                       else if (i == eListID) {
                                cprintf("List-ID: %s%s", mptr, nl);
                        }
                        else if (i == 'V') {
@@ -2129,7 +1777,7 @@ void OutputRFC822MsgHeaders(
                        }
                        else if (i == 'I')
                                safestrncpy(mid, mptr, sizeof_mid); /// TODO: detect @ here and copy @nodename in if not found.
-                       else if (i == 'F')
+                       else if (i == erFc822Addr)
                                safestrncpy(fuser, mptr, sizeof_fuser);
                        /* else if (i == 'O')
                           cprintf("X-Citadel-Room: %s%s",
@@ -2173,7 +1821,7 @@ void OutputRFC822MsgHeaders(
                                        }
                                }
                        }
-                       else if (i == 'K') {
+                       else if (i == eReplyTo) {
                                hptr = mptr;
                                while ((*hptr != '\0') && isspace(*hptr))
                                        hptr ++;
@@ -2205,7 +1853,7 @@ void Dump_RFC822HeadersBody(
        int nllen = strlen(nl);
        char *mptr;
 
-       mptr = TheMessage->cm_fields['M'];
+       mptr = TheMessage->cm_fields[eMesageText];
 
 
        prev_ch = '\0';
@@ -2286,7 +1934,7 @@ void DumpFormatFixed(
        int nllen = strlen (nl);
        char *mptr;
 
-       mptr = TheMessage->cm_fields['M'];
+       mptr = TheMessage->cm_fields[eMesageText];
        
        if (mode == MT_MIME) {
                cprintf("Content-type: text/plain\n\n");
@@ -2378,7 +2026,7 @@ int CtdlOutputPreLoadedMsg(
        strcpy(mid, "unknown");
        nl = (crlf ? "\r\n" : "\n");
 
-       if (!is_valid_message(TheMessage)) {
+       if (!CM_IsValidMsg(TheMessage)) {
                MSGM_syslog(LOG_ERR,
                            "ERROR: invalid preloaded message for output\n");
                cit_backtrace ();
@@ -2388,8 +2036,8 @@ int CtdlOutputPreLoadedMsg(
        /* 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['V'] != NULL) ) {
-               memset(TheMessage->cm_fields['V'], ' ', strlen(TheMessage->cm_fields['V']));
+       if ( (flags & SUPPRESS_ENV_TO) && (!CM_IsEmpty(TheMessage, eenVelopeTo)) ) {
+               memset(TheMessage->cm_fields[eenVelopeTo], ' ', strlen(TheMessage->cm_fields[eenVelopeTo]));
        }
                
        /* Are we downloading a MIME component? */
@@ -2404,7 +2052,7 @@ int CtdlOutputPreLoadedMsg(
                                ERROR + RESOURCE_BUSY);
                } else {
                        /* Parse the message text component */
-                       mptr = TheMessage->cm_fields['M'];
+                       mptr = TheMessage->cm_fields[eMesageText];
                        mime_parser(mptr, NULL, *mime_download, NULL, NULL, NULL, 0);
                        /* If there's no file open by this time, the requested
                         * section wasn't found, so print an error
@@ -2431,7 +2079,7 @@ int CtdlOutputPreLoadedMsg(
                        /* Parse the message text component */
                        int found_it = 0;
 
-                       mptr = TheMessage->cm_fields['M'];
+                       mptr = TheMessage->cm_fields[eMesageText];
                        mime_parser(mptr, NULL, *mime_spew_section, NULL, NULL, (void *)&found_it, 0);
                        /* If section wasn't found, print an error
                         */
@@ -2529,7 +2177,7 @@ START_TEXT:
        /* Tell the client about the MIME parts in this message */
        if (TheMessage->cm_format_type == FMT_RFC822) {
                if ( (mode == MT_CITADEL) || (mode == MT_MIME) ) {
-                       mptr = TheMessage->cm_fields['M'];
+                       mptr = TheMessage->cm_fields[eMesageText];
                        memset(&ma, 0, sizeof(struct ma_info));
                        mime_parser(mptr, NULL,
                                (do_proto ? *list_this_part : NULL),
@@ -2570,7 +2218,7 @@ START_TEXT:
         * message to the reader's screen width.
         */
        if (TheMessage->cm_format_type == FMT_CITADEL) {
-               mptr = TheMessage->cm_fields['M'];
+               mptr = TheMessage->cm_fields[eMesageText];
 
                if (mode == MT_MIME) {
                        cprintf("Content-type: text/x-citadel-variformat\n\n");
@@ -2611,141 +2259,6 @@ DONE:   /* now we're done */
        return(om_ok);
 }
 
-
-/*
- * display a message (mode 0 - Citadel proprietary)
- */
-void cmd_msg0(char *cmdbuf)
-{
-       long msgid;
-       int headers_only = HEADERS_ALL;
-
-       msgid = extract_long(cmdbuf, 0);
-       headers_only = extract_int(cmdbuf, 1);
-
-       CtdlOutputMsg(msgid, MT_CITADEL, headers_only, 1, 0, NULL, 0, NULL, NULL);
-       return;
-}
-
-
-/*
- * display a message (mode 2 - RFC822)
- */
-void cmd_msg2(char *cmdbuf)
-{
-       long msgid;
-       int headers_only = HEADERS_ALL;
-
-       msgid = extract_long(cmdbuf, 0);
-       headers_only = extract_int(cmdbuf, 1);
-
-       CtdlOutputMsg(msgid, MT_RFC822, headers_only, 1, 1, NULL, 0, NULL, NULL);
-}
-
-
-
-/* 
- * display a message (mode 3 - IGnet raw format - internal programs only)
- */
-void cmd_msg3(char *cmdbuf)
-{
-       long msgnum;
-       struct CtdlMessage *msg = NULL;
-       struct ser_ret smr;
-
-       if (CC->internal_pgm == 0) {
-               cprintf("%d This command is for internal programs only.\n",
-                       ERROR + HIGHER_ACCESS_REQUIRED);
-               return;
-       }
-
-       msgnum = extract_long(cmdbuf, 0);
-       msg = CtdlFetchMessage(msgnum, 1);
-       if (msg == NULL) {
-               cprintf("%d Message %ld not found.\n", 
-                       ERROR + MESSAGE_NOT_FOUND, msgnum);
-               return;
-       }
-
-       serialize_message(&smr, msg);
-       CtdlFreeMessage(msg);
-
-       if (smr.len == 0) {
-               cprintf("%d Unable to serialize message\n",
-                       ERROR + INTERNAL_ERROR);
-               return;
-       }
-
-       cprintf("%d %ld\n", BINARY_FOLLOWS, (long)smr.len);
-       client_write((char *)smr.ser, (int)smr.len);
-       free(smr.ser);
-}
-
-
-
-/* 
- * Display a message using MIME content types
- */
-void cmd_msg4(char *cmdbuf)
-{
-       long msgid;
-       char section[64];
-
-       msgid = extract_long(cmdbuf, 0);
-       extract_token(section, cmdbuf, 1, '|', sizeof section);
-       CtdlOutputMsg(msgid, MT_MIME, 0, 1, 0, (section[0] ? section : NULL) , 0, NULL, NULL);
-}
-
-
-
-/* 
- * Client tells us its preferred message format(s)
- */
-void cmd_msgp(char *cmdbuf)
-{
-       if (!strcasecmp(cmdbuf, "dont_decode")) {
-               CC->msg4_dont_decode = 1;
-               cprintf("%d MSG4 will not pre-decode messages.\n", CIT_OK);
-       }
-       else {
-               safestrncpy(CC->preferred_formats, cmdbuf, sizeof(CC->preferred_formats));
-               cprintf("%d Preferred MIME formats have been set.\n", CIT_OK);
-       }
-}
-
-
-/*
- * Open a component of a MIME message as a download file 
- */
-void cmd_opna(char *cmdbuf)
-{
-       long msgid;
-       char desired_section[128];
-
-       msgid = extract_long(cmdbuf, 0);
-       extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section);
-       safestrncpy(CC->download_desired_section, desired_section,
-               sizeof CC->download_desired_section);
-       CtdlOutputMsg(msgid, MT_DOWNLOAD, 0, 1, 1, NULL, 0, NULL, NULL);
-}                      
-
-
-/*
- * Open a component of a MIME message and transmit it all at once
- */
-void cmd_dlat(char *cmdbuf)
-{
-       long msgid;
-       char desired_section[128];
-
-       msgid = extract_long(cmdbuf, 0);
-       extract_token(desired_section, cmdbuf, 1, '|', sizeof desired_section);
-       safestrncpy(CC->download_desired_section, desired_section,
-               sizeof CC->download_desired_section);
-       CtdlOutputMsg(msgid, MT_SPEW_SECTION, 0, 1, 1, NULL, 0, NULL, NULL);
-}
-
-
 /*
  * Save one or more message pointers into a specified room
  * (Returns 0 for success, nonzero for failure)
@@ -2876,13 +2389,13 @@ int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newms
                                ReplicationChecks(msg);
                
                                /* If the message has an Exclusive ID, index that... */
-                               if (msg->cm_fields['E'] != NULL) {
-                                       index_message_by_euid(msg->cm_fields['E'], &CCC->room, msgid);
+                               if (!CM_IsEmpty(msg, eExclusiveID)) {
+                                       index_message_by_euid(msg->cm_fields[eExclusiveID], &CCC->room, msgid);
                                }
 
                                /* Free up the memory we may have allocated */
                                if (msg != supplied_msg) {
-                                       CtdlFreeMessage(msg);
+                                       CM_Free(msg);
                                }
                        }
        
@@ -2940,37 +2453,38 @@ long send_message(struct CtdlMessage *msg) {
        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['I']==NULL) {
-               msg->cm_fields['I'] = 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['M'] != NULL) {
-               if (strlen(msg->cm_fields['M']) > BIGMSG) {
+       if (!CM_IsEmpty(msg, eMesageText)) {
+               if (strlen(msg->cm_fields[eMesageText]) > BIGMSG) {
                        is_bigmsg = 1;
-                       holdM = msg->cm_fields['M'];
-                       msg->cm_fields['M'] = NULL;
+                       holdM = msg->cm_fields[eMesageText];
+                       msg->cm_fields[eMesageText] = NULL;
                }
        }
 
        /* Serialize our data structure for storage in the database */  
-       serialize_message(&smr, msg);
+       CtdlSerializeMessage(&smr, msg);
 
        if (is_bigmsg) {
-               msg->cm_fields['M'] = holdM;
+               msg->cm_fields[eMesageText] = holdM;
        }
 
        if (smr.len == 0) {
@@ -3014,39 +2528,37 @@ long send_message(struct CtdlMessage *msg) {
  * contains the length of the serialized message and a pointer to the
  * serialized message in memory.  THE LATTER MUST BE FREED BY THE CALLER.
  */
-void serialize_message(struct ser_ret *ret,            /* return values */
+void CtdlSerializeMessage(struct ser_ret *ret,         /* return values */
                       struct CtdlMessage *msg) /* unserialized msg */
 {
        struct CitContext *CCC = CC;
        size_t wlen, fieldlen;
        int i;
-       static char *forder = FORDER;
-       int n = sizeof(FORDER) - 1;
-       long lengths[sizeof(FORDER)];
+       long lengths[NDiskFields];
        
        memset(lengths, 0, sizeof(lengths));
 
        /*
         * Check for valid message format
         */
-       if (is_valid_message(msg) == 0) {
-               MSGM_syslog(LOG_ERR, "serialize_message() aborting due to invalid message\n");
+       if (CM_IsValidMsg(msg) == 0) {
+               MSGM_syslog(LOG_ERR, "CtdlSerializeMessage() aborting due to invalid message\n");
                ret->len = 0;
                ret->ser = NULL;
                return;
        }
 
        ret->len = 3;
-       for (i=0; i<n; ++i)
-               if (msg->cm_fields[(int)forder[i]] != NULL)
+       for (i=0; i < NDiskFields; ++i)
+               if (msg->cm_fields[FieldOrder[i]] != NULL)
                {
-                       lengths[i] = strlen(msg->cm_fields[(int)forder[i]]);
+                       lengths[i] = strlen(msg->cm_fields[FieldOrder[i]]);
                        ret->len += lengths[i] + 2;
                }
 
        ret->ser = malloc(ret->len);
        if (ret->ser == NULL) {
-               MSG_syslog(LOG_ERR, "serialize_message() malloc(%ld) failed: %s\n",
+               MSG_syslog(LOG_ERR, "CtdlSerializeMessage() malloc(%ld) failed: %s\n",
                           (long)ret->len, strerror(errno));
                ret->len = 0;
                ret->ser = NULL;
@@ -3058,14 +2570,14 @@ void serialize_message(struct ser_ret *ret,             /* return values */
        ret->ser[2] = msg->cm_format_type;
        wlen = 3;
 
-       for (i=0; i<n; ++i)
-               if (msg->cm_fields[(int)forder[i]] != NULL)
+       for (i=0; i < NDiskFields; ++i)
+               if (msg->cm_fields[FieldOrder[i]] != NULL)
                {
                        fieldlen = lengths[i];
-                       ret->ser[wlen++] = (char)forder[i];
+                       ret->ser[wlen++] = (char)FieldOrder[i];
 
                        memcpy(&ret->ser[wlen],
-                              msg->cm_fields[(int)forder[i]],
+                              msg->cm_fields[FieldOrder[i]],
                               fieldlen+1);
 
                        wlen = wlen + fieldlen + 1;
@@ -3095,12 +2607,12 @@ void ReplicationChecks(struct CtdlMessage *msg) {
 
        /* No exclusive id?  Don't do anything. */
        if (msg == NULL) return;
-       if (msg->cm_fields['E'] == NULL) return;
-       if (IsEmptyStr(msg->cm_fields['E'])) return;
+       if (CM_IsEmpty(msg, eExclusiveID)) return;
+
        /*MSG_syslog(LOG_DEBUG, "Exclusive ID: <%s> for room <%s>\n",
-         msg->cm_fields['E'], CCC->room.QRname);*/
+         msg->cm_fields[eExclusiveID], CCC->room.QRname);*/
 
-       old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields['E'], &CCC->room);
+       old_msgnum = CtdlLocateMessageByEuid(msg->cm_fields[eExclusiveID], &CCC->room);
        if (old_msgnum > 0L) {
                MSG_syslog(LOG_DEBUG, "ReplicationChecks() replacing message %ld\n", old_msgnum);
                CtdlDeleteMessages(CCC->room.QRname, &old_msgnum, 1, "");
@@ -3119,7 +2631,6 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        )
 {
        char submit_filename[128];
-       char generated_timestamp[32];
        char hold_rm[ROOMNAMELEN];
        char actual_rm[ROOMNAMELEN];
        char force_room[ROOMNAMELEN];
@@ -3147,41 +2658,40 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
        int rv = 0;
 
        MSGM_syslog(LOG_DEBUG, "CtdlSubmitMsg() called\n");
-       if (is_valid_message(msg) == 0) return(-1);     /* self check */
+       if (CM_IsValidMsg(msg) == 0) return(-1);        /* self check */
 
        /* If this message has no timestamp, we take the liberty of
         * giving it one, right now.
         */
-       if (msg->cm_fields['T'] == NULL) {
-               snprintf(generated_timestamp, sizeof generated_timestamp, "%ld", (long)time(NULL));
-               msg->cm_fields['T'] = 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['P'] == NULL) {
-               if (msg->cm_fields['A'] != NULL) {
-                       msg->cm_fields['P'] = strdup(msg->cm_fields['A']);
-                       for (a=0; !IsEmptyStr(&msg->cm_fields['P'][a]); ++a) {
-                               if (isspace(msg->cm_fields['P'][a])) {
-                                       msg->cm_fields['P'][a] = ' ';
+       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['P'] = 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['M'] == NULL) {
+       if (CM_IsEmpty(msg, eMesageText)) {
                MSGM_syslog(LOG_ERR, "ERROR: attempt to save message with NULL body\n");
                return(-2);
        }
@@ -3195,7 +2705,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                break;
        case 4:
                strcpy(content_type, "text/plain");
-               mptr = bmstrcasestr(msg->cm_fields['M'], "Content-type:");
+               mptr = bmstrcasestr(msg->cm_fields[eMesageText], "Content-type:");
                if (mptr != NULL) {
                        char *aptr;
                        safestrncpy(content_type, &mptr[13], sizeof content_type);
@@ -3245,8 +2755,8 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        /*
         * If this message has no O (room) field, generate one.
         */
-       if (msg->cm_fields['O'] == NULL) {
-               msg->cm_fields['O'] = 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) */
@@ -3341,7 +2851,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                snprintf(bounce_to, sizeof bounce_to, "%s@%s", CCC->user.fullname, config.c_nodename);
        }
        else {
-               snprintf(bounce_to, sizeof bounce_to, "%s@%s", msg->cm_fields['A'], msg->cm_fields['N']);
+               snprintf(bounce_to, sizeof bounce_to, "%s@%s", msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]);
        }
 
        /* If this is private, local mail, make a copy in the
@@ -3349,8 +2859,10 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,      /* message to save */
         */
        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) {
@@ -3361,13 +2873,17 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
                                        /* 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));
@@ -3375,13 +2891,13 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
                                        imsg->cm_magic = CTDLMESSAGE_MAGIC;
                                        imsg->cm_anon_type = MES_NORMAL;
                                        imsg->cm_format_type = FMT_RFC822;
-                                       imsg->cm_fields['U'] = strdup("QMSG");
-                                       imsg->cm_fields['A'] = strdup("Citadel");
-                                       imsg->cm_fields['J'] = strdup("do not journal");
-                                       imsg->cm_fields['M'] = instr;   /* imsg owns this memory now */
-                                       imsg->cm_fields['2'] = 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);
+                                       CM_Free(imsg);
                                }
                        }
                        else {
@@ -3392,12 +2908,10 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
 
        /* Perform "after save" hooks */
        MSGM_syslog(LOG_DEBUG, "Performing after-save hooks\n");
-       if (msg->cm_fields['3'] != NULL) free(msg->cm_fields['3']);
-       msg->cm_fields['3'] = malloc(20);
-       snprintf(msg->cm_fields['3'], 20, "%ld", newmsgid);
+
+       CM_SetFieldLONG(msg, eVltMsgNum, newmsgid);
        PerformMessageHooks(msg, EVT_AFTERSAVE);
-       free(msg->cm_fields['3']);
-       msg->cm_fields['3'] = 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
@@ -3412,14 +2926,14 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
                        extract_token(recipient, recps->recp_ignet, i,
                                      '|', sizeof recipient);
 
-                       hold_R = msg->cm_fields['R'];
-                       hold_D = msg->cm_fields['D'];
-                       msg->cm_fields['R'] = malloc(SIZ);
-                       msg->cm_fields['D'] = malloc(128);
-                       extract_token(msg->cm_fields['R'], recipient, 0, '@', SIZ);
-                       extract_token(msg->cm_fields['D'], recipient, 1, '@', 128);
+                       hold_R = msg->cm_fields[eRecipient];
+                       hold_D = msg->cm_fields[eDestination];
+                       msg->cm_fields[eRecipient] = malloc(SIZ);
+                       msg->cm_fields[eDestination] = malloc(128);
+                       extract_token(msg->cm_fields[eRecipient], recipient, 0, '@', SIZ);
+                       extract_token(msg->cm_fields[eDestination], recipient, 1, '@', 128);
                
-                       serialize_message(&smr, msg);
+                       CtdlSerializeMessage(&smr, msg);
                        if (smr.len > 0) {
                                snprintf(submit_filename, sizeof submit_filename,
                                         "%s/netmail.%04lx.%04x.%04x",
@@ -3437,10 +2951,10 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
                                free(smr.ser);
                        }
 
-                       free(msg->cm_fields['R']);
-                       free(msg->cm_fields['D']);
-                       msg->cm_fields['R'] = hold_R;
-                       msg->cm_fields['D'] = hold_D;
+                       free(msg->cm_fields[eRecipient]);
+                       free(msg->cm_fields[eDestination]);
+                       msg->cm_fields[eRecipient] = hold_R;
+                       msg->cm_fields[eDestination] = hold_D;
                }
 
        /* Go back to the room we started from */
@@ -3496,12 +3010,12 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,     /* message to save */
                imsg->cm_magic = CTDLMESSAGE_MAGIC;
                imsg->cm_anon_type = MES_NORMAL;
                imsg->cm_format_type = FMT_RFC822;
-               imsg->cm_fields['U'] = strdup("QMSG");
-               imsg->cm_fields['A'] = strdup("Citadel");
-               imsg->cm_fields['J'] = strdup("do not journal");
-               imsg->cm_fields['M'] = SmashStrBuf(&SpoolMsg);  /* imsg owns this memory now */
+               imsg->cm_fields[eMsgSubject] = strdup("QMSG");
+               imsg->cm_fields[eAuthor] = strdup("Citadel");
+               imsg->cm_fields[eJournal] = strdup("do not journal");
+               imsg->cm_fields[eMesageText] = SmashStrBuf(&SpoolMsg);  /* imsg owns this memory now */
                CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR);
-               CtdlFreeMessage(imsg);
+               CM_Free(imsg);
        }
 
        /*
@@ -3527,7 +3041,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        /*
         * Determine whether this message qualifies for journaling.
         */
-       if (msg->cm_fields['J'] != NULL) {
+       if (!CM_IsEmpty(msg, eJournal)) {
                qualified_for_journaling = 0;
        }
        else {
@@ -3582,32 +3096,32 @@ void quickie_message(const char *from,
        msg->cm_format_type = format_type;
 
        if (from != NULL) {
-               msg->cm_fields['A'] = strdup(from);
+               msg->cm_fields[eAuthor] = strdup(from);
        }
        else if (fromaddr != NULL) {
-               msg->cm_fields['A'] = strdup(fromaddr);
-               if (strchr(msg->cm_fields['A'], '@')) {
-                       *strchr(msg->cm_fields['A'], '@') = 0;
+               msg->cm_fields[eAuthor] = strdup(fromaddr);
+               if (strchr(msg->cm_fields[eAuthor], '@')) {
+                       *strchr(msg->cm_fields[eAuthor], '@') = 0;
                }
        }
        else {
-               msg->cm_fields['A'] = strdup("Citadel");
+               msg->cm_fields[eAuthor] = strdup("Citadel");
        }
 
-       if (fromaddr != NULL) msg->cm_fields['F'] = strdup(fromaddr);
-       if (room != NULL) msg->cm_fields['O'] = strdup(room);
-       msg->cm_fields['N'] = strdup(NODENAME);
+       if (fromaddr != NULL) msg->cm_fields[erFc822Addr] = strdup(fromaddr);
+       if (room != NULL) msg->cm_fields[eOriginalRoom] = strdup(room);
+       msg->cm_fields[eNodeName] = strdup(NODENAME);
        if (to != NULL) {
-               msg->cm_fields['R'] = strdup(to);
+               msg->cm_fields[eRecipient] = strdup(to);
                recp = validate_recipients(to, NULL, 0);
        }
        if (subject != NULL) {
-               msg->cm_fields['U'] = strdup(subject);
+               msg->cm_fields[eMsgSubject] = strdup(subject);
        }
-       msg->cm_fields['M'] = strdup(text);
+       msg->cm_fields[eMesageText] = strdup(text);
 
        CtdlSubmitMsg(msg, recp, room, 0);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        if (recp != NULL) free_recipients(recp);
 }
 
@@ -3944,7 +3458,7 @@ char *CtdlReadMessageBody(char *terminator,       /* token signalling EOT */
  * (NOTE: if you supply 'preformatted_text', the buffer you give it
  * will become part of the message.  This means you are no longer
  * responsible for managing that memory -- it will be freed along with
- * the rest of the fields when CtdlFreeMessage() is called.)
+ * the rest of the fields when CM_Free() is called.)
  */
 
 struct CtdlMessage *CtdlMakeMessage(
@@ -3983,16 +3497,16 @@ struct CtdlMessage *CtdlMakeMessage(
        if (my_email == NULL) my_email = "";
 
        if (!IsEmptyStr(my_email)) {
-               msg->cm_fields['P'] = strdup(my_email);
+               msg->cm_fields[eMessagePath] = strdup(my_email);
        }
        else {
                snprintf(buf, sizeof buf, "%s", author->fullname);
-               msg->cm_fields['P'] = strdup(buf);
+               msg->cm_fields[eMessagePath] = strdup(buf);
        }
-       convert_spaces_to_underscores(msg->cm_fields['P']);
+       convert_spaces_to_underscores(msg->cm_fields[eMessagePath]);
 
        snprintf(buf, sizeof buf, "%ld", (long)time(NULL));     /* timestamp */
-       msg->cm_fields['T'] = strdup(buf);
+       msg->cm_fields[eTimestamp] = strdup(buf);
 
        if ((fake_name != NULL) && (fake_name[0])) {            /* author */
                FakeAuthor = NewStrBufPlain (fake_name, -1);
@@ -4001,34 +3515,34 @@ struct CtdlMessage *CtdlMakeMessage(
                FakeAuthor = NewStrBufPlain (author->fullname, -1);
        }
        StrBufRFC2047encode(&FakeEncAuthor, FakeAuthor);
-       msg->cm_fields['A'] = SmashStrBuf(&FakeEncAuthor);
+       msg->cm_fields[eAuthor] = SmashStrBuf(&FakeEncAuthor);
        FreeStrBuf(&FakeAuthor);
 
        if (CC->room.QRflags & QR_MAILBOX) {            /* room */
-               msg->cm_fields['O'] = strdup(&CC->room.QRname[11]);
+               msg->cm_fields[eOriginalRoom] = strdup(&CC->room.QRname[11]);
        }
        else {
-               msg->cm_fields['O'] = strdup(CC->room.QRname);
+               msg->cm_fields[eOriginalRoom] = strdup(CC->room.QRname);
        }
 
-       msg->cm_fields['N'] = strdup(NODENAME);         /* nodename */
-       msg->cm_fields['H'] = strdup(HUMANNODE);                /* hnodename */
+       msg->cm_fields[eNodeName] = strdup(NODENAME);           /* nodename */
+       msg->cm_fields[eHumanNode] = strdup(HUMANNODE);         /* hnodename */
 
        if ((recipient != NULL) && (recipient[0] != 0)) {
-               msg->cm_fields['R'] = strdup(recipient);
+               msg->cm_fields[eRecipient] = strdup(recipient);
        }
        if ((recp_cc != NULL) && (recp_cc[0] != 0)) {
-               msg->cm_fields['Y'] = strdup(recp_cc);
+               msg->cm_fields[eCarbonCopY] = strdup(recp_cc);
        }
        if (dest_node[0] != 0) {
-               msg->cm_fields['D'] = strdup(dest_node);
+               msg->cm_fields[eDestination] = strdup(dest_node);
        }
 
        if (!IsEmptyStr(my_email)) {
-               msg->cm_fields['F'] = strdup(my_email);
+               msg->cm_fields[erFc822Addr] = strdup(my_email);
        }
        else if ( (author == &CC->user) && (!IsEmptyStr(CC->cs_inet_email)) ) {
-               msg->cm_fields['F'] = strdup(CC->cs_inet_email);
+               msg->cm_fields[erFc822Addr] = strdup(CC->cs_inet_email);
        }
 
        if (subject != NULL) {
@@ -4044,749 +3558,35 @@ struct CtdlMessage *CtdlMakeMessage(
                               (IsAscii = isascii(subject[i]) != 0 ))
                                i++;
                        if (IsAscii != 0)
-                               msg->cm_fields['U'] = strdup(subject);
+                               msg->cm_fields[eMsgSubject] = strdup(subject);
                        else /* ok, we've got utf8 in the string. */
                        {
-                               msg->cm_fields['U'] = rfc2047encode(subject, length);
+                               msg->cm_fields[eMsgSubject] = rfc2047encode(subject, length);
                        }
 
                }
        }
 
        if (supplied_euid != NULL) {
-               msg->cm_fields['E'] = strdup(supplied_euid);
+               msg->cm_fields[eExclusiveID] = strdup(supplied_euid);
        }
 
        if ((references != NULL) && (!IsEmptyStr(references))) {
-               if (msg->cm_fields['W'] != NULL)
-                       free(msg->cm_fields['W']);
-               msg->cm_fields['W'] = strdup(references);
+               if (msg->cm_fields[eWeferences] != NULL)
+                       free(msg->cm_fields[eWeferences]);
+               msg->cm_fields[eWeferences] = strdup(references);
        }
 
        if (preformatted_text != NULL) {
-               msg->cm_fields['M'] = preformatted_text;
+               msg->cm_fields[eMesageText] = preformatted_text;
        }
        else {
-               msg->cm_fields['M'] = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
+               msg->cm_fields[eMesageText] = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0);
        }
 
        return(msg);
 }
 
-/*
- * Check to see whether we have permission to post a message in the current
- * room.  Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or
- * returns 0 on success.
- */
-int CtdlDoIHavePermissionToPostInThisRoom(
-       char *errmsgbuf, 
-       size_t n, 
-       const char* RemoteIdentifier,
-       int PostPublic,
-       int is_reply
-       ) {
-       int ra;
-
-       if (!(CC->logged_in) && 
-           (PostPublic == POST_LOGGED_IN)) {
-               snprintf(errmsgbuf, n, "Not logged in.");
-               return (ERROR + NOT_LOGGED_IN);
-       }
-       else if (PostPublic == CHECK_EXISTANCE) {
-               return (0); // We're Evaling whether a recipient exists
-       }
-       else if (!(CC->logged_in)) {
-               
-               if ((CC->room.QRflags & QR_READONLY)) {
-                       snprintf(errmsgbuf, n, "Not logged in.");
-                       return (ERROR + NOT_LOGGED_IN);
-               }
-               if (CC->room.QRflags2 & QR2_MODERATED) {
-                       snprintf(errmsgbuf, n, "Not logged in Moderation feature not yet implemented!");
-                       return (ERROR + NOT_LOGGED_IN);
-               }
-               if ((PostPublic!=POST_LMTP) &&(CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) {
-
-                       return CtdlNetconfigCheckRoomaccess(errmsgbuf, n, RemoteIdentifier);
-               }
-               return (0);
-
-       }
-
-       if ((CC->user.axlevel < AxProbU)
-           && ((CC->room.QRflags & QR_MAILBOX) == 0)) {
-               snprintf(errmsgbuf, n, "Need to be validated to enter (except in %s> to sysop)", MAILROOM);
-               return (ERROR + HIGHER_ACCESS_REQUIRED);
-       }
-
-       CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
-
-       if (ra & UA_POSTALLOWED) {
-               strcpy(errmsgbuf, "OK to post or reply here");
-               return(0);
-       }
-
-       if ( (ra & UA_REPLYALLOWED) && (is_reply) ) {
-               /*
-                * To be thorough, we ought to check to see if the message they are
-                * replying to is actually a valid one in this room, but unless this
-                * actually becomes a problem we'll go with high performance instead.
-                */
-               strcpy(errmsgbuf, "OK to reply here");
-               return(0);
-       }
-
-       if ( (ra & UA_REPLYALLOWED) && (!is_reply) ) {
-               /* Clarify what happened with a better error message */
-               snprintf(errmsgbuf, n, "You may only reply to existing messages here.");
-               return (ERROR + HIGHER_ACCESS_REQUIRED);
-       }
-
-       snprintf(errmsgbuf, n, "Higher access is required to post in this room.");
-       return (ERROR + HIGHER_ACCESS_REQUIRED);
-
-}
-
-
-/*
- * Check to see if the specified user has Internet mail permission
- * (returns nonzero if permission is granted)
- */
-int CtdlCheckInternetMailPermission(struct ctdluser *who) {
-
-       /* Do not allow twits to send Internet mail */
-       if (who->axlevel <= AxProbU) return(0);
-
-       /* Globally enabled? */
-       if (config.c_restrict == 0) return(1);
-
-       /* User flagged ok? */
-       if (who->flags & US_INTERNET) return(2);
-
-       /* Admin level access? */
-       if (who->axlevel >= AxAideU) return(3);
-
-       /* No mail for you! */
-       return(0);
-}
-
-
-/*
- * Validate recipients, count delivery types and errors, and handle aliasing
- * FIXME check for dupes!!!!!
- *
- * Returns 0 if all addresses are ok, ret->num_error = -1 if no addresses 
- * were specified, or the number of addresses found invalid.
- *
- * Caller needs to free the result using free_recipients()
- */
-struct recptypes *validate_recipients(const char *supplied_recipients, 
-                                     const char *RemoteIdentifier, 
-                                     int Flags) {
-       struct CitContext *CCC = CC;
-       struct recptypes *ret;
-       char *recipients = NULL;
-       char *org_recp;
-       char this_recp[256];
-       char this_recp_cooked[256];
-       char append[SIZ];
-       long len;
-       int num_recps = 0;
-       int i, j;
-       int mailtype;
-       int invalid;
-       struct ctdluser tempUS;
-       struct ctdlroom tempQR;
-       struct ctdlroom tempQR2;
-       int err = 0;
-       char errmsg[SIZ];
-       int in_quotes = 0;
-
-       /* Initialize */
-       ret = (struct recptypes *) malloc(sizeof(struct recptypes));
-       if (ret == NULL) return(NULL);
-
-       /* Set all strings to null and numeric values to zero */
-       memset(ret, 0, sizeof(struct recptypes));
-
-       if (supplied_recipients == NULL) {
-               recipients = strdup("");
-       }
-       else {
-               recipients = strdup(supplied_recipients);
-       }
-
-       /* Allocate some memory.  Yes, this allocates 500% more memory than we will
-        * actually need, but it's healthier for the heap than doing lots of tiny
-        * realloc() calls instead.
-        */
-       len = strlen(recipients) + 1024;
-       ret->errormsg = malloc(len);
-       ret->recp_local = malloc(len);
-       ret->recp_internet = malloc(len);
-       ret->recp_ignet = malloc(len);
-       ret->recp_room = malloc(len);
-       ret->display_recp = malloc(len);
-       ret->recp_orgroom = malloc(len);
-       org_recp = malloc(len);
-
-       ret->errormsg[0] = 0;
-       ret->recp_local[0] = 0;
-       ret->recp_internet[0] = 0;
-       ret->recp_ignet[0] = 0;
-       ret->recp_room[0] = 0;
-       ret->recp_orgroom[0] = 0;
-       ret->display_recp[0] = 0;
-
-       ret->recptypes_magic = RECPTYPES_MAGIC;
-
-       /* Change all valid separator characters to commas */
-       for (i=0; !IsEmptyStr(&recipients[i]); ++i) {
-               if ((recipients[i] == ';') || (recipients[i] == '|')) {
-                       recipients[i] = ',';
-               }
-       }
-
-       /* Now start extracting recipients... */
-
-       while (!IsEmptyStr(recipients)) {
-               for (i=0; i<=strlen(recipients); ++i) {
-                       if (recipients[i] == '\"') in_quotes = 1 - in_quotes;
-                       if ( ( (recipients[i] == ',') && (!in_quotes) ) || (recipients[i] == 0) ) {
-                               safestrncpy(this_recp, recipients, i+1);
-                               this_recp[i] = 0;
-                               if (recipients[i] == ',') {
-                                       strcpy(recipients, &recipients[i+1]);
-                               }
-                               else {
-                                       strcpy(recipients, "");
-                               }
-                               break;
-                       }
-               }
-
-               striplt(this_recp);
-               if (IsEmptyStr(this_recp))
-                       break;
-               MSG_syslog(LOG_DEBUG, "Evaluating recipient #%d: %s\n", num_recps, this_recp);
-               ++num_recps;
-
-               strcpy(org_recp, this_recp);
-               alias(this_recp);
-               alias(this_recp);
-               mailtype = alias(this_recp);
-
-               for (j = 0; !IsEmptyStr(&this_recp[j]); ++j) {
-                       if (this_recp[j]=='_') {
-                               this_recp_cooked[j] = ' ';
-                       }
-                       else {
-                               this_recp_cooked[j] = this_recp[j];
-                       }
-               }
-               this_recp_cooked[j] = '\0';
-               invalid = 0;
-               errmsg[0] = 0;
-               switch(mailtype) {
-               case MES_LOCAL:
-                       if (!strcasecmp(this_recp, "sysop")) {
-                               ++ret->num_room;
-                               strcpy(this_recp, config.c_aideroom);
-                               if (!IsEmptyStr(ret->recp_room)) {
-                                       strcat(ret->recp_room, "|");
-                               }
-                               strcat(ret->recp_room, this_recp);
-                       }
-                       else if ( (!strncasecmp(this_recp, "room_", 5))
-                                 && (!CtdlGetRoom(&tempQR, &this_recp_cooked[5])) ) {
-
-                               /* Save room so we can restore it later */
-                               tempQR2 = CCC->room;
-                               CCC->room = tempQR;
-                                       
-                               /* Check permissions to send mail to this room */
-                               err = CtdlDoIHavePermissionToPostInThisRoom(
-                                       errmsg, 
-                                       sizeof errmsg, 
-                                       RemoteIdentifier,
-                                       Flags,
-                                       0                       /* 0 = not a reply */
-                                       );
-                               if (err)
-                               {
-                                       ++ret->num_error;
-                                       invalid = 1;
-                               } 
-                               else {
-                                       ++ret->num_room;
-                                       if (!IsEmptyStr(ret->recp_room)) {
-                                               strcat(ret->recp_room, "|");
-                                       }
-                                       strcat(ret->recp_room, &this_recp_cooked[5]);
-
-                                       if (!IsEmptyStr(ret->recp_orgroom)) {
-                                               strcat(ret->recp_orgroom, "|");
-                                       }
-                                       strcat(ret->recp_orgroom, org_recp);
-
-                               }
-                                       
-                               /* Restore room in case something needs it */
-                               CCC->room = tempQR2;
-
-                       }
-                       else if (CtdlGetUser(&tempUS, this_recp) == 0) {
-                               ++ret->num_local;
-                               strcpy(this_recp, tempUS.fullname);
-                               if (!IsEmptyStr(ret->recp_local)) {
-                                       strcat(ret->recp_local, "|");
-                               }
-                               strcat(ret->recp_local, this_recp);
-                       }
-                       else if (CtdlGetUser(&tempUS, this_recp_cooked) == 0) {
-                               ++ret->num_local;
-                               strcpy(this_recp, tempUS.fullname);
-                               if (!IsEmptyStr(ret->recp_local)) {
-                                       strcat(ret->recp_local, "|");
-                               }
-                               strcat(ret->recp_local, this_recp);
-                       }
-                       else {
-                               ++ret->num_error;
-                               invalid = 1;
-                       }
-                       break;
-               case MES_INTERNET:
-                       /* Yes, you're reading this correctly: if the target
-                        * domain points back to the local system or an attached
-                        * Citadel directory, the address is invalid.  That's
-                        * because if the address were valid, we would have
-                        * already translated it to a local address by now.
-                        */
-                       if (IsDirectory(this_recp, 0)) {
-                               ++ret->num_error;
-                               invalid = 1;
-                       }
-                       else {
-                               ++ret->num_internet;
-                               if (!IsEmptyStr(ret->recp_internet)) {
-                                       strcat(ret->recp_internet, "|");
-                               }
-                               strcat(ret->recp_internet, this_recp);
-                       }
-                       break;
-               case MES_IGNET:
-                       ++ret->num_ignet;
-                       if (!IsEmptyStr(ret->recp_ignet)) {
-                               strcat(ret->recp_ignet, "|");
-                       }
-                       strcat(ret->recp_ignet, this_recp);
-                       break;
-               case MES_ERROR:
-                       ++ret->num_error;
-                       invalid = 1;
-                       break;
-               }
-               if (invalid) {
-                       if (IsEmptyStr(errmsg)) {
-                               snprintf(append, sizeof append, "Invalid recipient: %s", this_recp);
-                       }
-                       else {
-                               snprintf(append, sizeof append, "%s", errmsg);
-                       }
-                       if ( (strlen(ret->errormsg) + strlen(append) + 3) < SIZ) {
-                               if (!IsEmptyStr(ret->errormsg)) {
-                                       strcat(ret->errormsg, "; ");
-                               }
-                               strcat(ret->errormsg, append);
-                       }
-               }
-               else {
-                       if (IsEmptyStr(ret->display_recp)) {
-                               strcpy(append, this_recp);
-                       }
-                       else {
-                               snprintf(append, sizeof append, ", %s", this_recp);
-                       }
-                       if ( (strlen(ret->display_recp)+strlen(append)) < SIZ) {
-                               strcat(ret->display_recp, append);
-                       }
-               }
-       }
-       free(org_recp);
-
-       if ((ret->num_local + ret->num_internet + ret->num_ignet +
-            ret->num_room + ret->num_error) == 0) {
-               ret->num_error = (-1);
-               strcpy(ret->errormsg, "No recipients specified.");
-       }
-
-       MSGM_syslog(LOG_DEBUG, "validate_recipients()\n");
-       MSG_syslog(LOG_DEBUG, " local: %d <%s>\n", ret->num_local, ret->recp_local);
-       MSG_syslog(LOG_DEBUG, "  room: %d <%s>\n", ret->num_room, ret->recp_room);
-       MSG_syslog(LOG_DEBUG, "  inet: %d <%s>\n", ret->num_internet, ret->recp_internet);
-       MSG_syslog(LOG_DEBUG, " ignet: %d <%s>\n", ret->num_ignet, ret->recp_ignet);
-       MSG_syslog(LOG_DEBUG, " error: %d <%s>\n", ret->num_error, ret->errormsg);
-
-       free(recipients);
-       return(ret);
-}
-
-
-/*
- * Destructor for struct recptypes
- */
-void free_recipients(struct recptypes *valid) {
-
-       if (valid == NULL) {
-               return;
-       }
-
-       if (valid->recptypes_magic != RECPTYPES_MAGIC) {
-               struct CitContext *CCC = CC;
-               MSGM_syslog(LOG_EMERG, "Attempt to call free_recipients() on some other data type!\n");
-               abort();
-       }
-
-       if (valid->errormsg != NULL)            free(valid->errormsg);
-       if (valid->recp_local != NULL)          free(valid->recp_local);
-       if (valid->recp_internet != NULL)       free(valid->recp_internet);
-       if (valid->recp_ignet != NULL)          free(valid->recp_ignet);
-       if (valid->recp_room != NULL)           free(valid->recp_room);
-       if (valid->recp_orgroom != NULL)        free(valid->recp_orgroom);
-       if (valid->display_recp != NULL)        free(valid->display_recp);
-       if (valid->bounce_to != NULL)           free(valid->bounce_to);
-       if (valid->envelope_from != NULL)       free(valid->envelope_from);
-       if (valid->sending_room != NULL)        free(valid->sending_room);
-       free(valid);
-}
-
-
-
-/*
- * message entry  -  mode 0 (normal)
- */
-void cmd_ent0(char *entargs)
-{
-       struct CitContext *CCC = CC;
-       int post = 0;
-       char recp[SIZ];
-       char cc[SIZ];
-       char bcc[SIZ];
-       char supplied_euid[128];
-       int anon_flag = 0;
-       int format_type = 0;
-       char newusername[256];
-       char newuseremail[256];
-       struct CtdlMessage *msg;
-       int anonymous = 0;
-       char errmsg[SIZ];
-       int err = 0;
-       struct recptypes *valid = NULL;
-       struct recptypes *valid_to = NULL;
-       struct recptypes *valid_cc = NULL;
-       struct recptypes *valid_bcc = NULL;
-       char subject[SIZ];
-       int subject_required = 0;
-       int do_confirm = 0;
-       long msgnum;
-       int i, j;
-       char buf[256];
-       int newuseremail_ok = 0;
-       char references[SIZ];
-       char *ptr;
-
-       unbuffer_output();
-
-       post = extract_int(entargs, 0);
-       extract_token(recp, entargs, 1, '|', sizeof recp);
-       anon_flag = extract_int(entargs, 2);
-       format_type = extract_int(entargs, 3);
-       extract_token(subject, entargs, 4, '|', sizeof subject);
-       extract_token(newusername, entargs, 5, '|', sizeof newusername);
-       do_confirm = extract_int(entargs, 6);
-       extract_token(cc, entargs, 7, '|', sizeof cc);
-       extract_token(bcc, entargs, 8, '|', sizeof bcc);
-       switch(CC->room.QRdefaultview) {
-       case VIEW_NOTES:
-       case VIEW_WIKI:
-               extract_token(supplied_euid, entargs, 9, '|', sizeof supplied_euid);
-               break;
-       default:
-               supplied_euid[0] = 0;
-               break;
-       }
-       extract_token(newuseremail, entargs, 10, '|', sizeof newuseremail);
-       extract_token(references, entargs, 11, '|', sizeof references);
-       for (ptr=references; *ptr != 0; ++ptr) {
-               if (*ptr == '!') *ptr = '|';
-       }
-
-       /* first check to make sure the request is valid. */
-
-       err = CtdlDoIHavePermissionToPostInThisRoom(
-               errmsg,
-               sizeof errmsg,
-               NULL,
-               POST_LOGGED_IN,
-               (!IsEmptyStr(references))               /* is this a reply?  or a top-level post? */
-               );
-       if (err)
-       {
-               cprintf("%d %s\n", err, errmsg);
-               return;
-       }
-
-       /* Check some other permission type things. */
-
-       if (IsEmptyStr(newusername)) {
-               strcpy(newusername, CCC->user.fullname);
-       }
-       if (  (CCC->user.axlevel < AxAideU)
-             && (strcasecmp(newusername, CCC->user.fullname))
-             && (strcasecmp(newusername, CCC->cs_inet_fn))
-               ) {     
-               cprintf("%d You don't have permission to author messages as '%s'.\n",
-                       ERROR + HIGHER_ACCESS_REQUIRED,
-                       newusername
-                       );
-               return;
-       }
-
-
-       if (IsEmptyStr(newuseremail)) {
-               newuseremail_ok = 1;
-       }
-
-       if (!IsEmptyStr(newuseremail)) {
-               if (!strcasecmp(newuseremail, CCC->cs_inet_email)) {
-                       newuseremail_ok = 1;
-               }
-               else if (!IsEmptyStr(CCC->cs_inet_other_emails)) {
-                       j = num_tokens(CCC->cs_inet_other_emails, '|');
-                       for (i=0; i<j; ++i) {
-                               extract_token(buf, CCC->cs_inet_other_emails, i, '|', sizeof buf);
-                               if (!strcasecmp(newuseremail, buf)) {
-                                       newuseremail_ok = 1;
-                               }
-                       }
-               }
-       }
-
-       if (!newuseremail_ok) {
-               cprintf("%d You don't have permission to author messages as '%s'.\n",
-                       ERROR + HIGHER_ACCESS_REQUIRED,
-                       newuseremail
-                       );
-               return;
-       }
-
-       CCC->cs_flags |= CS_POSTING;
-
-       /* In mailbox rooms we have to behave a little differently --
-        * make sure the user has specified at least one recipient.  Then
-        * validate the recipient(s).  We do this for the Mail> room, as
-        * well as any room which has the "Mailbox" view set - unless it
-        * is the DRAFTS room which does not require recipients
-        */
-
-       if ( (  ( (CCC->room.QRflags & QR_MAILBOX) && (!strcasecmp(&CCC->room.QRname[11], MAILROOM)) )
-               || ( (CCC->room.QRflags & QR_MAILBOX) && (CCC->curr_view == VIEW_MAILBOX) )
-                    ) && (strcasecmp(&CCC->room.QRname[11], USERDRAFTROOM)) !=0 ) {
-               if (CCC->user.axlevel < AxProbU) {
-                       strcpy(recp, "sysop");
-                       strcpy(cc, "");
-                       strcpy(bcc, "");
-               }
-
-               valid_to = validate_recipients(recp, NULL, 0);
-               if (valid_to->num_error > 0) {
-                       cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_to->errormsg);
-                       free_recipients(valid_to);
-                       return;
-               }
-
-               valid_cc = validate_recipients(cc, NULL, 0);
-               if (valid_cc->num_error > 0) {
-                       cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_cc->errormsg);
-                       free_recipients(valid_to);
-                       free_recipients(valid_cc);
-                       return;
-               }
-
-               valid_bcc = validate_recipients(bcc, NULL, 0);
-               if (valid_bcc->num_error > 0) {
-                       cprintf("%d %s\n", ERROR + NO_SUCH_USER, valid_bcc->errormsg);
-                       free_recipients(valid_to);
-                       free_recipients(valid_cc);
-                       free_recipients(valid_bcc);
-                       return;
-               }
-
-               /* Recipient required, but none were specified */
-               if ( (valid_to->num_error < 0) && (valid_cc->num_error < 0) && (valid_bcc->num_error < 0) ) {
-                       free_recipients(valid_to);
-                       free_recipients(valid_cc);
-                       free_recipients(valid_bcc);
-                       cprintf("%d At least one recipient is required.\n", ERROR + NO_SUCH_USER);
-                       return;
-               }
-
-               if (valid_to->num_internet + valid_cc->num_internet + valid_bcc->num_internet > 0) {
-                       if (CtdlCheckInternetMailPermission(&CCC->user)==0) {
-                               cprintf("%d You do not have permission "
-                                       "to send Internet mail.\n",
-                                       ERROR + HIGHER_ACCESS_REQUIRED);
-                               free_recipients(valid_to);
-                               free_recipients(valid_cc);
-                               free_recipients(valid_bcc);
-                               return;
-                       }
-               }
-
-               if ( ( (valid_to->num_internet + valid_to->num_ignet + valid_cc->num_internet + valid_cc->num_ignet + valid_bcc->num_internet + valid_bcc->num_ignet) > 0)
-                    && (CCC->user.axlevel < AxNetU) ) {
-                       cprintf("%d Higher access required for network mail.\n",
-                               ERROR + HIGHER_ACCESS_REQUIRED);
-                       free_recipients(valid_to);
-                       free_recipients(valid_cc);
-                       free_recipients(valid_bcc);
-                       return;
-               }
-       
-               if ((RESTRICT_INTERNET == 1)
-                   && (valid_to->num_internet + valid_cc->num_internet + valid_bcc->num_internet > 0)
-                   && ((CCC->user.flags & US_INTERNET) == 0)
-                   && (!CCC->internal_pgm)) {
-                       cprintf("%d You don't have access to Internet mail.\n",
-                               ERROR + HIGHER_ACCESS_REQUIRED);
-                       free_recipients(valid_to);
-                       free_recipients(valid_cc);
-                       free_recipients(valid_bcc);
-                       return;
-               }
-
-       }
-
-       /* Is this a room which has anonymous-only or anonymous-option? */
-       anonymous = MES_NORMAL;
-       if (CCC->room.QRflags & QR_ANONONLY) {
-               anonymous = MES_ANONONLY;
-       }
-       if (CCC->room.QRflags & QR_ANONOPT) {
-               if (anon_flag == 1) {   /* only if the user requested it */
-                       anonymous = MES_ANONOPT;
-               }
-       }
-
-       if ((CCC->room.QRflags & QR_MAILBOX) == 0) {
-               recp[0] = 0;
-       }
-
-       /* Recommend to the client that the use of a message subject is
-        * strongly recommended in this room, if either the SUBJECTREQ flag
-        * is set, or if there is one or more Internet email recipients.
-        */
-       if (CCC->room.QRflags2 & QR2_SUBJECTREQ) subject_required = 1;
-       if ((valid_to)  && (valid_to->num_internet > 0))        subject_required = 1;
-       if ((valid_cc)  && (valid_cc->num_internet > 0))        subject_required = 1;
-       if ((valid_bcc) && (valid_bcc->num_internet > 0))       subject_required = 1;
-
-       /* If we're only checking the validity of the request, return
-        * success without creating the message.
-        */
-       if (post == 0) {
-               cprintf("%d %s|%d\n", CIT_OK,
-                       ((valid_to != NULL) ? valid_to->display_recp : ""), 
-                       subject_required);
-               free_recipients(valid_to);
-               free_recipients(valid_cc);
-               free_recipients(valid_bcc);
-               return;
-       }
-
-       /* We don't need these anymore because we'll do it differently below */
-       free_recipients(valid_to);
-       free_recipients(valid_cc);
-       free_recipients(valid_bcc);
-
-       /* Read in the message from the client. */
-       if (do_confirm) {
-               cprintf("%d send message\n", START_CHAT_MODE);
-       } else {
-               cprintf("%d send message\n", SEND_LISTING);
-       }
-
-       msg = CtdlMakeMessage(&CCC->user, recp, cc,
-                             CCC->room.QRname, anonymous, format_type,
-                             newusername, newuseremail, subject,
-                             ((!IsEmptyStr(supplied_euid)) ? supplied_euid : NULL),
-                             NULL, references);
-
-       /* Put together one big recipients struct containing to/cc/bcc all in
-        * one.  This is for the envelope.
-        */
-       char *all_recps = malloc(SIZ * 3);
-       strcpy(all_recps, recp);
-       if (!IsEmptyStr(cc)) {
-               if (!IsEmptyStr(all_recps)) {
-                       strcat(all_recps, ",");
-               }
-               strcat(all_recps, cc);
-       }
-       if (!IsEmptyStr(bcc)) {
-               if (!IsEmptyStr(all_recps)) {
-                       strcat(all_recps, ",");
-               }
-               strcat(all_recps, bcc);
-       }
-       if (!IsEmptyStr(all_recps)) {
-               valid = validate_recipients(all_recps, NULL, 0);
-       }
-       else {
-               valid = NULL;
-       }
-       free(all_recps);
-
-       if ((valid != NULL) && (valid->num_room == 1))
-       {
-               /* posting into an ML room? set the envelope from 
-                * to the actual mail address so others get a valid
-                * reply-to-header.
-                */
-               msg->cm_fields['V'] = strdup(valid->recp_orgroom);
-       }
-
-       if (msg != NULL) {
-               msgnum = CtdlSubmitMsg(msg, valid, "", QP_EADDR);
-               if (do_confirm) {
-                       cprintf("%ld\n", msgnum);
-
-                       if (StrLength(CCC->StatusMessage) > 0) {
-                               cprintf("%s\n", ChrPtr(CCC->StatusMessage));
-                       }
-                       else if (msgnum >= 0L) {
-                               client_write(HKEY("Message accepted.\n"));
-                       }
-                       else {
-                               client_write(HKEY("Internal error.\n"));
-                       }
-
-                       if (msg->cm_fields['E'] != NULL) {
-                               cprintf("%s\n", msg->cm_fields['E']);
-                       } else {
-                               cprintf("\n");
-                       }
-                       cprintf("000\n");
-               }
-
-               CtdlFreeMessage(msg);
-       }
-       if (valid != NULL) {
-               free_recipients(valid);
-       }
-       return;
-}
 
 
 
@@ -4939,179 +3739,6 @@ int CtdlDeleteMessages(char *room_name,         /* which room */
 
 
 
-/*
- * Check whether the current user has permission to delete messages from
- * the current room (returns 1 for yes, 0 for no)
- */
-int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void) {
-       int ra;
-       CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
-       if (ra & UA_DELETEALLOWED) return(1);
-       return(0);
-}
-
-
-
-
-/*
- * Delete message from current room
- */
-void cmd_dele(char *args)
-{
-       int num_deleted;
-       int i;
-       char msgset[SIZ];
-       char msgtok[32];
-       long *msgs;
-       int num_msgs = 0;
-
-       extract_token(msgset, args, 0, '|', sizeof msgset);
-       num_msgs = num_tokens(msgset, ',');
-       if (num_msgs < 1) {
-               cprintf("%d Nothing to do.\n", CIT_OK);
-               return;
-       }
-
-       if (CtdlDoIHavePermissionToDeleteMessagesFromThisRoom() == 0) {
-               cprintf("%d Higher access required.\n",
-                       ERROR + HIGHER_ACCESS_REQUIRED);
-               return;
-       }
-
-       /*
-        * Build our message set to be moved/copied
-        */
-       msgs = malloc(num_msgs * sizeof(long));
-       for (i=0; i<num_msgs; ++i) {
-               extract_token(msgtok, msgset, i, ',', sizeof msgtok);
-               msgs[i] = atol(msgtok);
-       }
-
-       num_deleted = CtdlDeleteMessages(CC->room.QRname, msgs, num_msgs, "");
-       free(msgs);
-
-       if (num_deleted) {
-               cprintf("%d %d message%s deleted.\n", CIT_OK,
-                       num_deleted, ((num_deleted != 1) ? "s" : ""));
-       } else {
-               cprintf("%d Message not found.\n", ERROR + MESSAGE_NOT_FOUND);
-       }
-}
-
-
-
-
-/*
- * move or copy a message to another room
- */
-void cmd_move(char *args)
-{
-       char msgset[SIZ];
-       char msgtok[32];
-       long *msgs;
-       int num_msgs = 0;
-
-       char targ[ROOMNAMELEN];
-       struct ctdlroom qtemp;
-       int err;
-       int is_copy = 0;
-       int ra;
-       int permit = 0;
-       int i;
-
-       extract_token(msgset, args, 0, '|', sizeof msgset);
-       num_msgs = num_tokens(msgset, ',');
-       if (num_msgs < 1) {
-               cprintf("%d Nothing to do.\n", CIT_OK);
-               return;
-       }
-
-       extract_token(targ, args, 1, '|', sizeof targ);
-       convert_room_name_macros(targ, sizeof targ);
-       targ[ROOMNAMELEN - 1] = 0;
-       is_copy = extract_int(args, 2);
-
-       if (CtdlGetRoom(&qtemp, targ) != 0) {
-               cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, targ);
-               return;
-       }
-
-       if (!strcasecmp(qtemp.QRname, CC->room.QRname)) {
-               cprintf("%d Source and target rooms are the same.\n", ERROR + ALREADY_EXISTS);
-               return;
-       }
-
-       CtdlGetUser(&CC->user, CC->curr_user);
-       CtdlRoomAccess(&qtemp, &CC->user, &ra, NULL);
-
-       /* Check for permission to perform this operation.
-        * Remember: "CC->room" is source, "qtemp" is target.
-        */
-       permit = 0;
-
-       /* Admins can move/copy */
-       if (CC->user.axlevel >= AxAideU) permit = 1;
-
-       /* Room aides can move/copy */
-       if (CC->user.usernum == CC->room.QRroomaide) permit = 1;
-
-       /* Permit move/copy from personal rooms */
-       if ((CC->room.QRflags & QR_MAILBOX)
-           && (qtemp.QRflags & QR_MAILBOX)) permit = 1;
-
-       /* Permit only copy from public to personal room */
-       if ( (is_copy)
-            && (!(CC->room.QRflags & QR_MAILBOX))
-            && (qtemp.QRflags & QR_MAILBOX)) permit = 1;
-
-       /* Permit message removal from collaborative delete rooms */
-       if (CC->room.QRflags2 & QR2_COLLABDEL) permit = 1;
-
-       /* Users allowed to post into the target room may move into it too. */
-       if ((CC->room.QRflags & QR_MAILBOX) && 
-           (qtemp.QRflags & UA_POSTALLOWED))  permit = 1;
-
-       /* User must have access to target room */
-       if (!(ra & UA_KNOWN))  permit = 0;
-
-       if (!permit) {
-               cprintf("%d Higher access required.\n",
-                       ERROR + HIGHER_ACCESS_REQUIRED);
-               return;
-       }
-
-       /*
-        * Build our message set to be moved/copied
-        */
-       msgs = malloc(num_msgs * sizeof(long));
-       for (i=0; i<num_msgs; ++i) {
-               extract_token(msgtok, msgset, i, ',', sizeof msgtok);
-               msgs[i] = atol(msgtok);
-       }
-
-       /*
-        * Do the copy
-        */
-       err = CtdlSaveMsgPointersInRoom(targ, msgs, num_msgs, 1, NULL, 0);
-       if (err != 0) {
-               cprintf("%d Cannot store message(s) in %s: error %d\n",
-                       err, targ, err);
-               free(msgs);
-               return;
-       }
-
-       /* Now delete the message from the source room,
-        * if this is a 'move' rather than a 'copy' operation.
-        */
-       if (is_copy == 0) {
-               CtdlDeleteMessages(CC->room.QRname, msgs, num_msgs, "");
-       }
-       free(msgs);
-
-       cprintf("%d Message(s) %s.\n", CIT_OK, (is_copy ? "copied" : "moved") );
-}
-
-
 
 /*
  * GetMetaData()  -  Get the supplementary record for a message
@@ -5441,13 +4068,13 @@ void CtdlWriteObject(char *req_room,                    /* Room to stuff it in */
        msg->cm_magic = CTDLMESSAGE_MAGIC;
        msg->cm_anon_type = MES_NORMAL;
        msg->cm_format_type = 4;
-       msg->cm_fields['A'] = strdup(CCC->user.fullname);
-       msg->cm_fields['O'] = strdup(req_room);
-       msg->cm_fields['N'] = strdup(config.c_nodename);
-       msg->cm_fields['H'] = strdup(config.c_humannode);
+       msg->cm_fields[eAuthor] = strdup(CCC->user.fullname);
+       msg->cm_fields[eOriginalRoom] = strdup(req_room);
+       msg->cm_fields[eNodeName] = strdup(config.c_nodename);
+       msg->cm_fields[eHumanNode] = strdup(config.c_humannode);
        msg->cm_flags = flags;
        
-       msg->cm_fields['M'] = encoded_message;
+       msg->cm_fields[eMesageText] = encoded_message;
 
        /* Create the requested room if we have to. */
        if (CtdlGetRoom(&qrbuf, roomname) != 0) {
@@ -5465,118 +4092,10 @@ void CtdlWriteObject(char *req_room,                   /* Room to stuff it in */
        }
        /* Now write the data */
        CtdlSubmitMsg(msg, NULL, roomname, 0);
-       CtdlFreeMessage(msg);
-}
-
-
-
-
-
-
-void CtdlGetSysConfigBackend(long msgnum, void *userdata) {
-       config_msgnum = msgnum;
-}
-
-
-char *CtdlGetSysConfig(char *sysconfname) {
-       char hold_rm[ROOMNAMELEN];
-       long msgnum;
-       char *conf;
-       struct CtdlMessage *msg;
-       char buf[SIZ];
-       
-       strcpy(hold_rm, CC->room.QRname);
-       if (CtdlGetRoom(&CC->room, SYSCONFIGROOM) != 0) {
-               CtdlGetRoom(&CC->room, hold_rm);
-               return NULL;
-       }
-
-
-       /* We want the last (and probably only) config in this room */
-       begin_critical_section(S_CONFIG);
-       config_msgnum = (-1L);
-       CtdlForEachMessage(MSGS_LAST, 1, NULL, sysconfname, NULL,
-                          CtdlGetSysConfigBackend, NULL);
-       msgnum = config_msgnum;
-       end_critical_section(S_CONFIG);
-
-       if (msgnum < 0L) {
-               conf = NULL;
-       }
-       else {
-               msg = CtdlFetchMessage(msgnum, 1);
-               if (msg != NULL) {
-                       conf = strdup(msg->cm_fields['M']);
-                       CtdlFreeMessage(msg);
-               }
-               else {
-                       conf = NULL;
-               }
-       }
-
-       CtdlGetRoom(&CC->room, hold_rm);
-
-       if (conf != NULL) do {
-                       extract_token(buf, conf, 0, '\n', sizeof buf);
-                       strcpy(conf, &conf[strlen(buf)+1]);
-               } while ( (!IsEmptyStr(conf)) && (!IsEmptyStr(buf)) );
-
-       return(conf);
-}
-
-
-void CtdlPutSysConfig(char *sysconfname, char *sysconfdata) {
-       CtdlWriteObject(SYSCONFIGROOM, sysconfname, sysconfdata, (strlen(sysconfdata)+1), NULL, 0, 1, 0);
-}
-
-
-/*
- * Determine whether a given Internet address belongs to the current user
- */
-int CtdlIsMe(char *addr, int addr_buf_len)
-{
-       struct recptypes *recp;
-       int i;
-
-       recp = validate_recipients(addr, NULL, 0);
-       if (recp == NULL) return(0);
-
-       if (recp->num_local == 0) {
-               free_recipients(recp);
-               return(0);
-       }
-
-       for (i=0; i<recp->num_local; ++i) {
-               extract_token(addr, recp->recp_local, i, '|', addr_buf_len);
-               if (!strcasecmp(addr, CC->user.fullname)) {
-                       free_recipients(recp);
-                       return(1);
-               }
-       }
-
-       free_recipients(recp);
-       return(0);
+       CM_Free(msg);
 }
 
 
-/*
- * Citadel protocol command to do the same
- */
-void cmd_isme(char *argbuf) {
-       char addr[256];
-
-       if (CtdlAccessCheck(ac_logged_in)) return;
-       extract_token(addr, argbuf, 0, '|', sizeof addr);
-
-       if (CtdlIsMe(addr, sizeof addr)) {
-               cprintf("%d %s\n", CIT_OK, addr);
-       }
-       else {
-               cprintf("%d Not you.\n", ERROR + ILLEGAL_VALUE);
-       }
-
-}
-
 
 /*****************************************************************************/
 /*                      MODULE INITIALIZATION STUFF                          */
@@ -5589,19 +4108,6 @@ CTDL_MODULE_INIT(msgbase)
 {
        if (!threading) {
                CtdlRegisterDebugFlagHook(HKEY("messages"), SetMessageDebugEnabled, &MessageDebugEnabled);
-
-               CtdlRegisterProtoHook(cmd_msgs, "MSGS", "Output a list of messages in the current room");
-               CtdlRegisterProtoHook(cmd_msg0, "MSG0", "Output a message in plain text format");
-               CtdlRegisterProtoHook(cmd_msg2, "MSG2", "Output a message in RFC822 format");
-               CtdlRegisterProtoHook(cmd_msg3, "MSG3", "Output a message in raw format (deprecated)");
-               CtdlRegisterProtoHook(cmd_msg4, "MSG4", "Output a message in the client's preferred format");
-               CtdlRegisterProtoHook(cmd_msgp, "MSGP", "Select preferred format for MSG4 output");
-               CtdlRegisterProtoHook(cmd_opna, "OPNA", "Open an attachment for download");
-               CtdlRegisterProtoHook(cmd_dlat, "DLAT", "Download an attachment");
-               CtdlRegisterProtoHook(cmd_ent0, "ENT0", "Enter a message");
-               CtdlRegisterProtoHook(cmd_dele, "DELE", "Delete a message");
-               CtdlRegisterProtoHook(cmd_move, "MOVE", "Move or copy a message to another room");
-               CtdlRegisterProtoHook(cmd_isme, "ISME", "Determine whether an email address belongs to a user");
        }
 
         /* return our Subversion id for the Log */
index e9f8a3f84313682041e2a6696038c5834bf15742..59ee421e01e2dec32c076f8b2e56838ce6647bde 100644 (file)
@@ -59,27 +59,6 @@ struct repl {                        /* Info for replication checking */
 };
 
 
-/* Data structure returned by validate_recipients() */
-struct recptypes {
-       int recptypes_magic;
-        int num_local;
-        int num_internet;
-        int num_ignet;
-       int num_room;
-        int num_error;
-       char *errormsg;
-       char *recp_local;
-       char *recp_internet;
-       char *recp_ignet;
-       char *recp_room;
-       char *recp_orgroom;
-       char *display_recp;
-       char *bounce_to;
-       char *envelope_from;
-       char *sending_room;
-};
-
-#define RECPTYPES_MAGIC 0xfeeb
 
 /*
  * This is a list of "harvested" email addresses that we might want to
@@ -94,20 +73,8 @@ struct addresses_to_be_filed {
 
 extern struct addresses_to_be_filed *atbf;
 
-int alias (char *name);
-void cmd_msgs (char *cmdbuf);
-void cmd_isme (char *cmdbuf);
-void help_subst (char *strbuf, char *source, char *dest);
-void do_help_subst (char *buffer);
 void memfmout (char *mptr, const char *nl);
 void output_mime_parts(char *);
-void cmd_msg0 (char *cmdbuf);
-void cmd_msg2 (char *cmdbuf);
-void cmd_msg3 (char *cmdbuf);
-void cmd_msg4 (char *cmdbuf);
-void cmd_msgp (char *cmdbuf);
-void cmd_opna (char *cmdbuf);
-void cmd_dlat (char *cmdbuf);
 long send_message (struct CtdlMessage *);
 void loadtroom (void);
 long CtdlSubmitMsg(struct CtdlMessage *, struct recptypes *, const char *, int);
@@ -134,9 +101,6 @@ void flood_protect_quickie_message(const char *from,
                                   long ioid,
                                   time_t NOW);
 
-void cmd_ent0 (char *entargs);
-void cmd_dele (char *delstr);
-void cmd_move (char *args);
 void GetMetaData(struct MetaData *, long);
 void PutMetaData(struct MetaData *);
 void AdjRefCount(long, int);
@@ -163,12 +127,24 @@ void CtdlWriteObject(char *req_room,                      /* Room to stuff it in */
                        unsigned int flags              /* Internal save flags */
 );
 struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body);
-struct CtdlMessage * CtdlDuplicateMessage(struct CtdlMessage *OrgMsg);
-void CtdlMsgSetCM_Fields(struct CtdlMessage *Msg, const char which, const char *buf, long length);
-void CtdlFreeMessage(struct CtdlMessage *msg);
-void CtdlFreeMessageContents(struct CtdlMessage *msg);
-void serialize_message(struct ser_ret *, struct CtdlMessage *);
-int is_valid_message(struct CtdlMessage *);
+struct CtdlMessage * CM_Duplicate
+                       (struct CtdlMessage *OrgMsg);
+int  CM_IsEmpty        (struct CtdlMessage *Msg, eMsgField which);
+void CM_SetField       (struct CtdlMessage *Msg, eMsgField which, const char *buf, long length);
+void CM_SetFieldLONG   (struct CtdlMessage *Msg, eMsgField which, long lvalue);
+void CM_CopyField      (struct CtdlMessage *Msg, eMsgField WhichToPutTo, eMsgField WhichtToCopy);
+void CM_CutFieldAt     (struct CtdlMessage *Msg, eMsgField WhichToCut, long maxlen);
+void CM_FlushField     (struct CtdlMessage *Msg, eMsgField which);
+void CM_SetAsField     (struct CtdlMessage *Msg, eMsgField which, char **buf, long length);
+void CM_SetAsFieldSB   (struct CtdlMessage *Msg, eMsgField which, StrBuf **buf);
+void CM_GetAsField     (struct CtdlMessage *Msg, eMsgField which, char **ret, long *retlen);
+void CM_PrependToField (struct CtdlMessage *Msg, eMsgField which, const char *buf, long length);
+
+void CM_Free           (struct CtdlMessage *msg);
+void CM_FreeContents   (struct CtdlMessage *msg);
+int  CM_IsValidMsg     (struct CtdlMessage *msg);
+
+void CtdlSerializeMessage(struct ser_ret *, struct CtdlMessage *);
 void ReplicationChecks(struct CtdlMessage *);
 int CtdlSaveMsgPointersInRoom(char *roomname, long newmsgidlist[], int num_newmsgs,
                        int do_repl_check, struct CtdlMessage *supplied_msg, int suppress_refcount_adj);
@@ -207,22 +183,6 @@ int CtdlOutputPreLoadedMsg(struct CtdlMessage *,
                           int crlf,            /* 0=LF, 1=CRLF */
                           int flags            /* should the bessage be exported clean? */
 );
-int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void);
-int CtdlDoIHavePermissionToReadMessagesInThisRoom(void);
-
-enum {
-       POST_LOGGED_IN,
-       POST_EXTERNAL,
-       CHECK_EXISTANCE,
-       POST_LMTP
-};
-
-int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, 
-       size_t n, 
-       const char* RemoteIdentifier,
-       int PostPublic,
-       int is_reply
-);
 
 
 /* values for which_set */
@@ -235,11 +195,6 @@ void CtdlSetSeen(long *target_msgnums, int num_target_msgnums,
                struct ctdluser *which_user, struct ctdlroom *which_room);
 void CtdlGetSeen(char *buf, int which_set);
 
-struct recptypes *validate_recipients(const char *recipients,
-                                     const char *RemoteIdentifier, 
-                                     int Flags);
-
-void free_recipients(struct recptypes *);
 
 struct CtdlMessage *CtdlMakeMessage(
         struct ctdluser *author,        /* author's user structure */
@@ -255,7 +210,6 @@ struct CtdlMessage *CtdlMakeMessage(
         char *preformatted_text,        /* ...or NULL to read text from client */
        char *references                /* Thread references */
 );
-int CtdlCheckInternetMailPermission(struct ctdluser *who);
 int CtdlIsMe(char *addr, int addr_buf_len);
 
 /* 
index d1a7539ff2d721f7ffc9976450bbec42c8f74e3a..b673d389eea570dfdb8e79f56c61216195e1e58f 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "include/ctdl_module.h"
 #include "serv_extensions.h"
+#include "config.h"
 
 void vFreeRoomNetworkStruct(void *vOneRoomNetCfg);
 void FreeRoomNetworkStructContent(OneRoomNetCfg *OneRNCfg);
index 010fa12766a3e617e9adbe6df7de2395e9d1bb20..29fa36971788043db962f3cb47ccec23928e701c 100644 (file)
 
 struct floor *floorcache[MAXFLOORS];
 
+/* 
+ * Determine whether the currently logged in session has permission to read
+ * messages in the current room.
+ */
+int CtdlDoIHavePermissionToReadMessagesInThisRoom(void) {
+       if (    (!(CC->logged_in))
+               && (!(CC->internal_pgm))
+               && (!config.c_guest_logins)
+       ) {
+               return(om_not_logged_in);
+       }
+       return(om_ok);
+}
+
+/*
+ * Check to see whether we have permission to post a message in the current
+ * room.  Returns a *CITADEL ERROR CODE* and puts a message in errmsgbuf, or
+ * returns 0 on success.
+ */
+int CtdlDoIHavePermissionToPostInThisRoom(
+       char *errmsgbuf, 
+       size_t n, 
+       const char* RemoteIdentifier,
+       PostType PostPublic,
+       int is_reply
+       ) {
+       int ra;
+
+       if (!(CC->logged_in) && 
+           (PostPublic == POST_LOGGED_IN)) {
+               snprintf(errmsgbuf, n, "Not logged in.");
+               return (ERROR + NOT_LOGGED_IN);
+       }
+       else if (PostPublic == CHECK_EXISTANCE) {
+               return (0); // We're Evaling whether a recipient exists
+       }
+       else if (!(CC->logged_in)) {
+               
+               if ((CC->room.QRflags & QR_READONLY)) {
+                       snprintf(errmsgbuf, n, "Not logged in.");
+                       return (ERROR + NOT_LOGGED_IN);
+               }
+               if (CC->room.QRflags2 & QR2_MODERATED) {
+                       snprintf(errmsgbuf, n, "Not logged in Moderation feature not yet implemented!");
+                       return (ERROR + NOT_LOGGED_IN);
+               }
+               if ((PostPublic!=POST_LMTP) &&(CC->room.QRflags2 & QR2_SMTP_PUBLIC) == 0) {
+
+                       return CtdlNetconfigCheckRoomaccess(errmsgbuf, n, RemoteIdentifier);
+               }
+               return (0);
+
+       }
+
+       if ((CC->user.axlevel < AxProbU)
+           && ((CC->room.QRflags & QR_MAILBOX) == 0)) {
+               snprintf(errmsgbuf, n, "Need to be validated to enter (except in %s> to sysop)", MAILROOM);
+               return (ERROR + HIGHER_ACCESS_REQUIRED);
+       }
+
+       CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
+
+       if (ra & UA_POSTALLOWED) {
+               strcpy(errmsgbuf, "OK to post or reply here");
+               return(0);
+       }
+
+       if ( (ra & UA_REPLYALLOWED) && (is_reply) ) {
+               /*
+                * To be thorough, we ought to check to see if the message they are
+                * replying to is actually a valid one in this room, but unless this
+                * actually becomes a problem we'll go with high performance instead.
+                */
+               strcpy(errmsgbuf, "OK to reply here");
+               return(0);
+       }
+
+       if ( (ra & UA_REPLYALLOWED) && (!is_reply) ) {
+               /* Clarify what happened with a better error message */
+               snprintf(errmsgbuf, n, "You may only reply to existing messages here.");
+               return (ERROR + HIGHER_ACCESS_REQUIRED);
+       }
+
+       snprintf(errmsgbuf, n, "Higher access is required to post in this room.");
+       return (ERROR + HIGHER_ACCESS_REQUIRED);
+
+}
+
+/*
+ * Check whether the current user has permission to delete messages from
+ * the current room (returns 1 for yes, 0 for no)
+ */
+int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void) {
+       int ra;
+       CtdlRoomAccess(&CC->room, &CC->user, &ra, NULL);
+       if (ra & UA_DELETEALLOWED) return(1);
+       return(0);
+}
+
 /*
  * Retrieve access control information for any user/room pair
  */
index f4c7cf527c0e35f2261d83b580eb96b58cd84c41..20a8436541e6b2a752466ad86126cd0a1b02a145 100644 (file)
@@ -14,3 +14,18 @@ void list_roomname(struct ctdlroom *qrbuf, int ra, int current_view, int default
 void convert_room_name_macros(char *towhere, size_t maxlen);
 
 
+typedef enum _POST_TYPE{
+       POST_LOGGED_IN,
+       POST_EXTERNAL,
+       CHECK_EXISTANCE,
+       POST_LMTP
+}PostType;
+
+int CtdlDoIHavePermissionToPostInThisRoom(char *errmsgbuf, 
+       size_t n, 
+       const char* RemoteIdentifier,
+       PostType PostPublic,
+       int is_reply
+);
+int CtdlDoIHavePermissionToDeleteMessagesFromThisRoom(void);
+int CtdlDoIHavePermissionToReadMessagesInThisRoom(void);
index cc51ae933916b291a9d829643fb75878c1ca829c..5f45055112ccb2bc5320055b9d722d444788be6f 100755 (executable)
@@ -30,7 +30,7 @@ U_FILE="$CUR_DIR/modules_upgrade.c"
 
 /usr/bin/printf "Scanning extension modules for entry points.\n"
 
-STATIC_FIRST_MODULES="citserver control modules euidindex file_ops msgbase room_ops user_ops nttlist database"
+STATIC_FIRST_MODULES="citserver control modules euidindex file_ops msgbase ctdl_message room_ops user_ops nttlist database internet_addressing"
 DYNAMIC_MODULES=`grep CTDL_MODULE_INIT modules/*/*.c |$SED 's;.*(\(.*\));\1;'`
 if test -d user_modules; then 
     USER_MODULES=`grep CTDL_MODULE_INIT user_modules/*/*.c |$SED 's;.*(\(.*\));\1;'`
index cd8034d1918530299a11c34906595be076f68826..10e8bee731ff5e246c196e24c901ee50bc535472 100644 (file)
@@ -1,5 +1,3 @@
-
-
 #ifndef SERVER_H
 #define SERVER_H
 
@@ -138,8 +136,8 @@ enum {
        S_NETSPOOL,
        S_XMPP_QUEUE,
        S_SCHEDULE_LIST,
-       S_SINGLE_USER,
-       S_LDAP,
+       S_SINGLE_USER,
+       S_LDAP,
        S_IM_LOGS,
        MAX_SEMAPHORES
 };
@@ -167,7 +165,7 @@ enum {
 /*
  * Message format types in the database
  */
-#define        FMT_CITADEL     0       /* Citadel vari-format (proprietary) */
+#define FMT_CITADEL    0       /* Citadel vari-format (proprietary) */
 #define FMT_FIXED      1       /* Fixed format (proprietary)        */
 #define FMT_RFC822     4       /* Standard (headers are in M field) */
 
@@ -198,7 +196,7 @@ struct cdbdata {
 };
 
 
-/* 
+/*
  * Event types can't be enum'ed, because they must remain consistent between
  * builds (to allow for binary modules built somewhere else)
  */
@@ -275,12 +273,12 @@ struct arcq {
 };
 
 
-/* 
+/*
  * Serialization routines use this struct to return a pointer and a length
  */
 struct ser_ret {
-        size_t len;
-        unsigned char *ser;
+       size_t len;
+       unsigned char *ser;
 };
 
 
@@ -294,11 +292,40 @@ struct UseTable {
 
 
 
-/* Preferred field order                                                       */
+/* Preferred field order                                                       */
 /*               **********                    Important fields                */
 /*                         ***************     Semi-important fields           */
-/*                                        **    internal only                   */
-/*                                          *  Message text (MUST be last)     */
-#define FORDER "IPTAFONHRDBCEWJGKLQSVXZYU12M"
+/*                                        **   internal only                   */
+/*                                          *  Message text (MUST be last)     */
+///#define FORDER      "IPTAFONHRDBCEWJGKLQSVXZYU12M"
+
+typedef enum _MsgField {
+       eAuthor       = 'A',
+       eBig_message  = 'B',
+       eRemoteRoom   = 'C',
+       eDestination  = 'D',
+       eExclusiveID  = 'E',
+       erFc822Addr   = 'F',
+       eHumanNode    = 'H',
+       emessageId    = 'I',
+       eJournal      = 'J',
+       eReplyTo      = 'K',
+       eListID       = 'L',
+       eMesageText   = 'M',
+       eNodeName     = 'N',
+       eOriginalRoom = 'O',
+       eMessagePath  = 'P',
+       eRecipient    = 'R',
+       eSpecialField = 'S',
+       eTimestamp    = 'T',
+       eMsgSubject   = 'U',
+       eenVelopeTo   = 'V',
+       eWeferences   = 'W',
+       eCarbonCopY   = 'Y',
+       eErrorMsg     = '0',
+       eSuppressIdx  = '1',
+       eExtnotify    = '2',
+       eVltMsgNum    = '3'
+}eMsgField;
 
 #endif /* SERVER_H */
index c4fec985d563df1c9700b902982b5cf5fa40fce7..f8843269005be7c038ab1b2f3d81fb2e5f424604 100644 (file)
@@ -48,7 +48,7 @@ a separate Citadel password.
  
  usernum -- these are assigned sequentially, and NEVER REUSED.  This is
 important because it allows us to use this number in other data structures
-without having to worry about users being added/removed later on, as you'll
+ without having to worry about users being added/removed later on, as you'll
 see later in this document.
  
  
@@ -227,73 +227,98 @@ can do wildcard matching without worrying about unpacking binary data such
 as message ID's first.  To provide later downward compatability
 all software should be written to IGNORE fields not currently defined.
 
-                 The type bytes currently defined are:         
-
-BYTE   Mnemonic        Comments
-
-A      Author          Name of originator of message.
-B      Big message     This is a flag which indicates that the message is
-                        big, and Citadel is storing the body in a separate
-                        record.  You will never see this field because the
-                        internal API handles it.
-D      Destination     Contains name of the system this message should
+                 The type bytes currently defined are:
+
+BYTE   Mnemonic        Enum / Comments
+
+A      Author          eAuthor
+                       Name of originator of message.
+B      Big message     eBig_message
+                       This is a flag which indicates that the message is
+                       big, and Citadel is storing the body in a separate
+                       record.  You will never see this field because the
+                       internal API handles it.
+C      RemoteRoom      eRemoteRoom
+                       when sent via Citadel Networking, this is the room
+                       its going to be put on the remote site.
+D      Destination     eDestination
+                       Contains name of the system this message should
                        be sent to, for mail routing (private mail only).
-E      Exclusive ID    A persistent alphanumeric Message ID used for
+E      Exclusive ID    eExclusiveID
+                       A persistent alphanumeric Message ID used for
                        network replication.  When a message arrives that
                        contains an Exclusive ID, any existing messages which
                        contain the same Exclusive ID and are *older* than this
                        message should be deleted.  If there exist any messages
                        with the same Exclusive ID that are *newer*, then this
                        message should be dropped.
-F      rFc822 address  For Internet mail, this is the delivery address of the
+F      rFc822 address  erFc822Addr
+                       For Internet mail, this is the delivery address of the
                        message author.
-H      Human node name Human-readable name of system message originated on.
-I      Message ID      An RFC822-compatible message ID for this message.
-J      Journal         The presence of this field indicates that the message
+H      Human node name eHumanNode
+                       Human-readable name of system message originated on.
+I      Message ID      emessageId
+                       An RFC822-compatible message ID for this message.
+J      Journal         eJournal
+                       The presence of this field indicates that the message
                        is disqualified from being journaled, perhaps because
                        it is itself a journalized message and we wish to
                        avoid double journaling.
-K       Reply-To        the Reply-To header for mailinglist outbound messages
-L      List-ID         Mailing list identification, as per RFC 2919
-M      Message Text    Normal ASCII, newlines seperated by CR's or LF's,
-                        null terminated as always.
-N      Nodename        Contains node name of system message originated on.
-O      Room            Room of origin.
-P      Path            Complete path of message, as in the UseNet news
+K      Reply-To        eReplyTo
+                       the Reply-To header for mailinglist outbound messages
+L      List-ID         eListID
+                       Mailing list identification, as per RFC 2919
+M      Message Text    eMesageText
+                       Normal ASCII, newlines seperated by CR's or LF's,
+                       null terminated as always.
+N      Nodename        eNodeName
+                       Contains node name of system message originated on.
+O      Room            eOriginalRoom - Room of origin.
+P      Path            eMessagePath
+                       Complete path of message, as in the UseNet news
                        standard.  A user should be able to send Internet mail
                        to this path. (Note that your system name will not be
                        tacked onto this until you're sending the message to
                        someone else)
-R      Recipient       Only present in Mail messages.
-S       Special field   Only meaningful for messages being spooled over a
-                        network.  Usually means that the message isn't really
-                        a message, but rather some other network function:
-                        -> "S" followed by "FILE" (followed by a null, of
-                           course) means that the message text is actually an
-                           IGnet/Open file transfer.  (OBSOLETE)
+R      Recipient       eRecipient - Only present in Mail messages.
+S      Special field   eSpecialField
+                       Only meaningful for messages being spooled over a
+                       network.  Usually means that the message isn't really
+                       a message, but rather some other network function:
+                       -> "S" followed by "FILE" (followed by a null, of
+                          course) means that the message text is actually an
+                          IGnet/Open file transfer.  (OBSOLETE)
                        -> "S" followed by "CANCEL" means that this message
                           should be deleted from the local message base once
                           it has been replicated to all network systems.
-T      date/Time       Unix timestamp containing the creation date/time of
+T      date/Time       eTimestamp
+                       Unix timestamp containing the creation date/time of
                        the message.
-U       sUbject         Optional.  Developers may choose whether they wish to
-                        generate or display subject fields.
-V      enVelope-to     The recipient specified in incoming SMTP messages.
-W      Wefewences      Previous message ID's for conversation threading.  When
+U      sUbject         eMsgSubject - Optional.
+                       Developers may choose whether they wish to
+                       generate or display subject fields.
+V      enVelope-to     eenVelopeTo
+                       The recipient specified in incoming SMTP messages.
+W      Wefewences      eWeferences
+                       Previous message ID's for conversation threading.  When
                        converting from RFC822 we use References: if present, or
                        In-Reply-To: otherwise.
                        (Who in extnotify spool messages which don't need to know
                        other message ids)
-Y      carbon copY     Optional, and only in Mail messages.
-0      Error           This field is typically never found in a message on
+Y      carbon copY     eCarbonCopY
+                       Optional, and only in Mail messages.
+0      Error           eErrorMsg
+                       This field is typically never found in a message on
                        disk or in transit.  Message scanning modules are
                        expected to fill in this field when rejecting a message
                        with an explanation as to what happened (virus found,
                        message looks like spam, etc.)
-1      suppress index  The presence of this field indicates that the message is
+1      suppress index  eSuppressIdx
+                       The presence of this field indicates that the message is
                        disqualified from being added to the full text index.
-2      extnotify       Used internally by the serv_extnotify module.
-3      msgnum          Used internally to pass the local message number in the
+2      extnotify       eExtnotify - Used internally by the serv_extnotify module.
+3      msgnum          eVltMsgNum
+                       Used internally to pass the local message number in the
                        database to after-save hooks.  Discarded afterwards.
   
                        EXAMPLE
index fd8056559c4ba479eaec5eb8570c63ebf11ca47c..eb91dcdac0980951ebaafb165872773be47d20bb 100644 (file)
@@ -61,6 +61,7 @@
 #include "context.h"
 #include "ctdl_module.h"
 #include "user_ops.h"
+#include "internet_addressing.h"
 
 /* These pipes are used to talk to the chkpwd daemon, which is forked during startup */
 int chkpwd_write_pipe[2];
@@ -368,6 +369,29 @@ void MailboxName(char *buf, size_t n, const struct ctdluser *who, const char *pr
 }
 
 
+/*
+ * Check to see if the specified user has Internet mail permission
+ * (returns nonzero if permission is granted)
+ */
+int CtdlCheckInternetMailPermission(struct ctdluser *who) {
+
+       /* Do not allow twits to send Internet mail */
+       if (who->axlevel <= AxProbU) return(0);
+
+       /* Globally enabled? */
+       if (config.c_restrict == 0) return(1);
+
+       /* User flagged ok? */
+       if (who->flags & US_INTERNET) return(2);
+
+       /* Admin level access? */
+       if (who->axlevel >= AxAideU) return(3);
+
+       /* No mail for you! */
+       return(0);
+}
+
+
 /*
  * Is the user currently logged in an Admin?
  */
index 3afe55013250e39fcaf495079f9db904e453661e..03133c2a384674796f6b59ffe6b58780dc680c5b 100644 (file)
@@ -14,6 +14,7 @@ void putuser (struct ctdluser *) __attribute__ ((deprecated));
 void lputuser (struct ctdluser *) __attribute__ ((deprecated));
 int is_aide (void);
 int is_room_aide (void);
+int CtdlCheckInternetMailPermission(struct ctdluser *who);
 /* getuserbynumber is deprecated, use CtdlGetUserByNumber instead */
 int getuserbynumber (struct ctdluser *usbuf, long int number) __attribute__ ((deprecated));
 void rebuild_usersbynumber(void);
index 62beeac8720102483fb8ae383fdd901597040474..af6e16c170421fd097ee2468b26fc3d551452d60 100644 (file)
@@ -441,7 +441,7 @@ char *bmstrcasestr_len(char *text, size_t textlen, const char *pattern, size_t p
 const char *cbmstrcasestr(const char *text, const char *pattern);
 const char *cbmstrcasestr_len(const char *text, size_t textlen, const char *pattern, size_t patlen);
 void CtdlMakeTempFileName(char *name, int len);
-char *rfc2047encode(char *line, long length);
+char *rfc2047encode(const char *line, long length);
 int is_msg_in_mset(const char *mset, long msgnum);
 int pattern2(char *search, char *patn);
 void stripltlen(char *, int *);
index c0d3f9f1e00f0ef063ae6482f0785b84980cabfb..2eafddaaaa4e602d865c1052581f23eb299a0f61 100644 (file)
@@ -445,9 +445,9 @@ int CtdlDecodeBase64(char *dest, const char *source, size_t length)
 /*
  * if we send out non ascii subjects, we encode it this way.
  */
-char *rfc2047encode(char *line, long length)
+char *rfc2047encode(const char *line, long length)
 {
-       char *AlreadyEncoded;
+       const char *AlreadyEncoded;
        char *result;
        long end;
 #define UTF8_HEADER "=?UTF-8?B?"