move email address related functions oven to internet_addressing
[citadel.git] / citadel / msgbase.c
index cc52aec73a6ab67abb45b58e5931f8357b8ad486..f079bdcdced1a506dfdf180d502f162b6b65c2df 100644 (file)
@@ -156,6 +156,13 @@ eMsgField FieldOrder[]  = {
 };
 
 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)
@@ -262,144 +269,89 @@ void CM_GetAsField(struct CtdlMessage *Msg, eMsgField which, char **ret, long *r
 }
 
 /*
- * This function is self explanatory.
- * (What can I say, I'm in a weird mood today...)
+ * 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 remove_any_whitespace_to_the_left_or_right_of_at_symbol(char *name)
+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 < 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]);
-                       }
+       for (i = 0; i < 256; ++i)
+               if (msg->cm_fields[i] != NULL) {
+                       free(msg->cm_fields[i]);
                }
-       }
-}
-
 
+       msg->cm_magic = 0;      /* just in case */
+}
 /*
- * Aliasing for network mail.
- * (Error messages have been commented out, because this is a server.)
+ * 'Destructor' for struct CtdlMessage
  */
-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);
-                       }
-               }
+void CM_Free(struct CtdlMessage *msg)
+{
+       if (CM_IsValidMsg(msg) == 0) 
+       {
+               if (msg != NULL) free (msg);
+               return;
        }
+       CM_FreeContents(msg);
+       free(msg);
+}
 
-       /* 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);
+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;
+}
 
-       /* figure out the delivery mode */
-       extract_token(node, name, 1, '@', sizeof node);
+struct CtdlMessage * CM_Duplicate(struct CtdlMessage *OrgMsg)
+{
+       int i;
+       struct CtdlMessage *NewMsg;
 
-       /* 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);
-       }
+       if (CM_IsValidMsg(OrgMsg) == 0) 
+               return NULL;
+       NewMsg = (struct CtdlMessage *)malloc(sizeof(struct CtdlMessage));
+       if (NewMsg == NULL)
+               return NULL;
 
-       /* 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);
+       memcpy(NewMsg, OrgMsg, sizeof(struct CtdlMessage));
 
-       /*
-        * 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);
+       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;
+                       }
                }
        }
-       free(ignetmap);
 
-       /* If we get to this point it's an invalid node name */
-       return (MES_ERROR);
+       return NewMsg;
 }
 
 
+
 /*
  * Back end for the MSGS command: output message number only.
  */
@@ -425,13 +377,13 @@ void headers_listing(long msgnum, void *userdata)
 
        cprintf("%ld|%s|%s|%s|%s|%s|\n",
                msgnum,
-               (msg->cm_fields[eTimestamp] ? msg->cm_fields[eTimestamp] : "0"),
-               (msg->cm_fields[eAuthor] ? msg->cm_fields[eAuthor] : ""),
-               (msg->cm_fields[eNodeName] ? msg->cm_fields[eNodeName] : ""),
-               (msg->cm_fields[erFc822Addr] ? msg->cm_fields[erFc822Addr] : ""),
-               (msg->cm_fields[eMsgSubject] ? msg->cm_fields[eMsgSubject] : "")
+               (!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"),
+               (!CM_IsEmpty(msg, eAuthor) ? msg->cm_fields[eAuthor] : ""),
+               (!CM_IsEmpty(msg, eNodeName) ? msg->cm_fields[eNodeName] : ""),
+               (!CM_IsEmpty(msg, erFc822Addr) ? msg->cm_fields[erFc822Addr] : ""),
+               (!CM_IsEmpty(msg, eMsgSubject) ? msg->cm_fields[eMsgSubject] : "")
        );
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 /*
@@ -449,9 +401,9 @@ void headers_euid(long msgnum, void *userdata)
 
        cprintf("%ld|%s|%s\n", 
                msgnum, 
-               (msg->cm_fields[eExclusiveID] ? msg->cm_fields[eExclusiveID] : ""),
-               (msg->cm_fields[eTimestamp] ? msg->cm_fields[eTimestamp] : "0"));
-       CtdlFreeMessage(msg);
+               (!CM_IsEmpty(msg, eExclusiveID) ? msg->cm_fields[eExclusiveID] : ""),
+               (!CM_IsEmpty(msg, eTimestamp) ? msg->cm_fields[eTimestamp] : "0"));
+       CM_Free(msg);
 }
 
 
@@ -851,7 +803,7 @@ int CtdlForEachMessage(int mode, long ref, char *search_string,
                                        if (CtdlMsgCmp(msg, compare)) {
                                                msglist[a] = 0L;
                                        }
-                                       CtdlFreeMessage(msg);
+                                       CM_Free(msg);
                                }
                        }
                }
@@ -1061,48 +1013,11 @@ void cmd_msgs(char *cmdbuf)
                           template,
                           CallBack,
                           NULL);
-       if (template != NULL) CtdlFreeMessage(template);
+       if (template != NULL) CM_Free(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
@@ -1398,20 +1313,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[eMesageText] == NULL) && (with_body) ) {
+       if ( (CM_IsEmpty(ret, eMesageText)) && (with_body) ) {
                dmsgtext = cdb_fetch(CDB_BIGMSGS, &msgnum, sizeof(long));
                if (dmsgtext != NULL) {
                        CM_SetAsField(ret, eMesageText, &dmsgtext->ptr, dmsgtext->len);
                        cdb_free(dmsgtext);
                }
        }
-       if (ret->cm_fields[eMesageText] == NULL) {
+       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;
        }
 
@@ -1419,89 +1334,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(eMsgField i, struct CtdlMessage *OrgMsg, struct CtdlMessage *NewMsg)
-{
-       long len;
-       len = strlen(OrgMsg->cm_fields[i]);
-       NewMsg->cm_fields[i] = malloc(len + 1);
-       if (NewMsg->cm_fields[i] == NULL)
-               return 0;
-       memcpy(NewMsg->cm_fields[i], OrgMsg->cm_fields[i], len);
-       NewMsg->cm_fields[i][len] = '\0';
-       return 1;
-}
-
-struct CtdlMessage * CtdlDuplicateMessage(struct CtdlMessage *OrgMsg)
-{
-       int i;
-       struct CtdlMessage *NewMsg;
-
-       if (is_valid_message(OrgMsg) == 0) 
-               return NULL;
-       NewMsg = (struct CtdlMessage *)malloc(sizeof(struct CtdlMessage));
-       if (NewMsg == NULL)
-               return NULL;
-
-       memcpy(NewMsg, OrgMsg, sizeof(struct CtdlMessage));
-
-       memset(&NewMsg->cm_fields, 0, sizeof(char*) * 256);
-       
-       for (i = 0; i < 256; ++i)
-       {
-               if (OrgMsg->cm_fields[i] != NULL)
-               {
-                       if (!DupCMField(i, OrgMsg, NewMsg))
-                       {
-                               CtdlFreeMessage(NewMsg);
-                               return NULL;
-                       }
-               }
-       }
-
-       return NewMsg;
-}
-
-
 
 /*
  * Pre callback function for multipart/alternative
@@ -1824,20 +1656,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)
@@ -1940,7 +1758,7 @@ int CtdlOutputMsg(long msg_num,           /* message number (local) to fetch */
                        *Address = TheMessage->cm_fields[erFc822Addr];
                        TheMessage->cm_fields[erFc822Addr] = NULL;
                }
-               CtdlFreeMessage(TheMessage);
+               CM_Free(TheMessage);
                TheMessage = NULL;
 
                if (encap.msg) {
@@ -1980,162 +1798,12 @@ int CtdlOutputMsg(long msg_num,                /* message number (local) to fetch */
                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,
@@ -2148,7 +1816,7 @@ void OutputCtdlMsgHeaders(
 
        /* begin header processing loop for Citadel message format */
        safestrncpy(display_name, "<unknown>", sizeof display_name);
-       if (TheMessage->cm_fields[eAuthor]) {
+       if (!CM_IsEmpty(TheMessage, eAuthor)) {
                strcpy(buf, TheMessage->cm_fields[eAuthor]);
                if (TheMessage->cm_anon_type == MES_ANONONLY) {
                        safestrncpy(display_name, "****", sizeof display_name);
@@ -2173,18 +1841,18 @@ void OutputCtdlMsgHeaders(
         * local Citadel network.
         */
        suppress_f = 0;
-       if (TheMessage->cm_fields[eNodeName] != NULL)
-               if (!IsEmptyStr(TheMessage->cm_fields[eNodeName]))
-                       if (haschar(TheMessage->cm_fields[eNodeName], '.') == 0) {
-                               suppress_f = 1;
-                       }
+       if (!CM_IsEmpty(TheMessage, eNodeName) &&
+           (haschar(TheMessage->cm_fields[eNodeName], '.') == 0))
+       {
+               suppress_f = 1;
+       }
 
        /* Now spew the header fields in the order we like them. */
        for (i=0; i< NDiskFields; ++i) {
                eMsgField Field;
                Field = FieldOrder[i];
                if (Field != eMesageText) {
-                       if ( (TheMessage->cm_fields[Field] != NULL)
+                       if ( (!CM_IsEmpty(TheMessage, Field))
                             && (msgkeys[Field] != NULL) ) {
                                if ((Field == eenVelopeTo) ||
                                    (Field == eRecipient) ||
@@ -2515,7 +2183,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 ();
@@ -2525,7 +2193,7 @@ 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[eenVelopeTo] != NULL) ) {
+       if ( (flags & SUPPRESS_ENV_TO) && (!CM_IsEmpty(TheMessage, eenVelopeTo)) ) {
                memset(TheMessage->cm_fields[eenVelopeTo], ' ', strlen(TheMessage->cm_fields[eenVelopeTo]));
        }
                
@@ -2805,7 +2473,7 @@ void cmd_msg3(char *cmdbuf)
        }
 
        serialize_message(&smr, msg);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 
        if (smr.len == 0) {
                cprintf("%d Unable to serialize message\n",
@@ -3013,13 +2681,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[eExclusiveID] != NULL) {
+                               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);
                                }
                        }
        
@@ -3091,12 +2759,12 @@ long send_message(struct CtdlMessage *msg) {
                );
 
        /* Generate an ID if we don't have one already */
-       if (msg->cm_fields[emessageId]==NULL) {
+       if (CM_IsEmpty(msg, emessageId)) {
                CM_SetField(msg, emessageId, msgidbuf, msgidbuflen);
        }
 
        /* If the message is big, set its body aside for storage elsewhere */
-       if (msg->cm_fields[eMesageText] != NULL) {
+       if (!CM_IsEmpty(msg, eMesageText)) {
                if (strlen(msg->cm_fields[eMesageText]) > BIGMSG) {
                        is_bigmsg = 1;
                        holdM = msg->cm_fields[eMesageText];
@@ -3165,7 +2833,7 @@ void serialize_message(struct ser_ret *ret,               /* return values */
        /*
         * Check for valid message format
         */
-       if (is_valid_message(msg) == 0) {
+       if (CM_IsValidMsg(msg) == 0) {
                MSGM_syslog(LOG_ERR, "serialize_message() aborting due to invalid message\n");
                ret->len = 0;
                ret->ser = NULL;
@@ -3231,8 +2899,8 @@ void ReplicationChecks(struct CtdlMessage *msg) {
 
        /* No exclusive id?  Don't do anything. */
        if (msg == NULL) return;
-       if (msg->cm_fields[eExclusiveID] == NULL) return;
-       if (IsEmptyStr(msg->cm_fields[eExclusiveID])) return;
+       if (CM_IsEmpty(msg, eExclusiveID)) return;
+
        /*MSG_syslog(LOG_DEBUG, "Exclusive ID: <%s> for room <%s>\n",
          msg->cm_fields[eExclusiveID], CCC->room.QRname);*/
 
@@ -3282,19 +2950,19 @@ 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[eTimestamp] == NULL) {
+       if (CM_IsEmpty(msg, eTimestamp)) {
                CM_SetFieldLONG(msg, eTimestamp, time(NULL));
        }
 
        /* If this message has no path, we generate one.
         */
-       if (msg->cm_fields[eMessagePath] == NULL) {
-               if (msg->cm_fields[eAuthor] != NULL) {
+       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])) {
@@ -3303,7 +2971,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                        }
                }
                else {
-                       CM_SetField(msg,eMessagePath, HKEY("unknown"));
+                       CM_SetField(msg, eMessagePath, HKEY("unknown"));
                }
        }
 
@@ -3315,7 +2983,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        }
 
        /* Learn about what's inside, because it's what's inside that counts */
-       if (msg->cm_fields[eMesageText] == NULL) {
+       if (CM_IsEmpty(msg, eMesageText)) {
                MSGM_syslog(LOG_ERR, "ERROR: attempt to save message with NULL body\n");
                return(-2);
        }
@@ -3379,7 +3047,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        /*
         * If this message has no O (room) field, generate one.
         */
-       if (msg->cm_fields[eOriginalRoom] == NULL) {
+       if (CM_IsEmpty(msg, eOriginalRoom)) {
                CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname));
        }
 
@@ -3521,7 +3189,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                                        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 {
@@ -3532,12 +3200,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[eVltMsgNum] != NULL) free(msg->cm_fields[eVltMsgNum]);
-       msg->cm_fields[eVltMsgNum] = malloc(20);
-       snprintf(msg->cm_fields[eVltMsgNum], 20, "%ld", newmsgid);
+
+       CM_SetFieldLONG(msg, eVltMsgNum, newmsgid);
        PerformMessageHooks(msg, EVT_AFTERSAVE);
-       free(msg->cm_fields[eVltMsgNum]);
-       msg->cm_fields[eVltMsgNum] = NULL;
+       CM_FlushField(msg, eVltMsgNum);
 
        /* For IGnet mail, we have to save a new copy into the spooler for
         * each recipient, with the R and D fields set to the recipient and
@@ -3641,7 +3307,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
                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);
        }
 
        /*
@@ -3667,7 +3333,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg,       /* message to save */
        /*
         * Determine whether this message qualifies for journaling.
         */
-       if (msg->cm_fields[eJournal] != NULL) {
+       if (!CM_IsEmpty(msg, eJournal)) {
                qualified_for_journaling = 0;
        }
        else {
@@ -3747,7 +3413,7 @@ void quickie_message(const char *from,
        msg->cm_fields[eMesageText] = strdup(text);
 
        CtdlSubmitMsg(msg, recp, room, 0);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        if (recp != NULL) free_recipients(recp);
 }
 
@@ -4084,7 +3750,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(
@@ -4213,394 +3879,6 @@ struct CtdlMessage *CtdlMakeMessage(
        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);
-}
-
 
 
 /*
@@ -4912,7 +4190,7 @@ void cmd_ent0(char *entargs)
                                client_write(HKEY("Internal error.\n"));
                        }
 
-                       if (msg->cm_fields[eExclusiveID] != NULL) {
+                       if (!CM_IsEmpty(msg, eExclusiveID)) {
                                cprintf("%s\n", msg->cm_fields[eExclusiveID]);
                        } else {
                                cprintf("\n");
@@ -4920,7 +4198,7 @@ void cmd_ent0(char *entargs)
                        cprintf("000\n");
                }
 
-               CtdlFreeMessage(msg);
+               CM_Free(msg);
        }
        if (valid != NULL) {
                free_recipients(valid);
@@ -5077,22 +4355,6 @@ int CtdlDeleteMessages(char *room_name,          /* which room */
        return (num_deleted);
 }
 
-
-
-/*
- * 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
  */
@@ -5605,7 +4867,7 @@ void CtdlWriteObject(char *req_room,                      /* Room to stuff it in */
        }
        /* Now write the data */
        CtdlSubmitMsg(msg, NULL, roomname, 0);
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
@@ -5647,7 +4909,7 @@ char *CtdlGetSysConfig(char *sysconfname) {
                msg = CtdlFetchMessage(msgnum, 1);
                if (msg != NULL) {
                        conf = strdup(msg->cm_fields[eMesageText]);
-                       CtdlFreeMessage(msg);
+                       CM_Free(msg);
                }
                else {
                        conf = NULL;
@@ -5670,53 +4932,6 @@ void CtdlPutSysConfig(char *sysconfname, char *sysconfdata) {
 }
 
 
-/*
- * 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);
-       }
-
-}
-
 
 /*****************************************************************************/
 /*                      MODULE INITIALIZATION STUFF                          */
@@ -5741,7 +4956,6 @@ CTDL_MODULE_INIT(msgbase)
                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 */