X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmsgbase.c;h=f079bdcdced1a506dfdf180d502f162b6b65c2df;hb=b03aed62997f838e8b75d12839398a999a8f9183;hp=cc52aec73a6ab67abb45b58e5931f8357b8ad486;hpb=848934c1722edc208c4df49c571586b72c3fc486;p=citadel.git diff --git a/citadel/msgbase.c b/citadel/msgbase.c index cc52aec73..f079bdcdc 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -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\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; icm_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, "", 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; inum_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 */