www.gusucode.com > VC++版的邮件服务器源程序源码程序 > VC++版的邮件服务器源程序源码程序\code\SMAILUtils.cpp
//Download by http://www.NewXing.com /* * XMail by Davide Libenzi ( Intranet and Internet mail server ) * Copyright (C) 1999,..,2004 Davide Libenzi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Davide Libenzi <davidel@xmailserver.org> * */ #include "SysInclude.h" #include "SysDep.h" #include "SvrDefines.h" #include "StrUtils.h" #include "SList.h" #include "ShBlocks.h" #include "ResLocks.h" #include "BuffSock.h" #include "UsrUtils.h" #include "SvrUtils.h" #include "MailConfig.h" #include "MessQueue.h" #include "SMAILUtils.h" #include "QueueUtils.h" #include "ExtAliases.h" #include "MiscUtils.h" #include "MailDomains.h" #include "Filter.h" #include "SMTPSvr.h" #include "SMTPUtils.h" #include "AppDefines.h" #include "MailSvr.h" #define SFF_HEADER_MODIFIED (1 << 0) #define STD_TAG_BUFFER_LENGTH 1024 #define CUSTOM_CMD_LINE_MAX 512 #define SMAIL_DOMAIN_PROC_DIR "custdomains" #define SMAIL_CMDALIAS_DIR "cmdaliases" #define SMAIL_DEFAULT_FILTER ".tab" #define SMAIL_LOG_FILE "smail" #define MAX_MTA_OPS 16 #define ADDRESS_TOKENIZER "," #define SMAIL_EXTERNAL_EXIT_BREAK 16 #define SMAIL_STOP_PROCESSING 3111965L struct SpoolFileData { char **ppszInfo; char **ppszFrom; char *pszMailFrom; char *pszSendMailFrom; char **ppszRcpt; char *pszRcptTo; char *pszSendRcptTo; char *pszRelayDomain; char szSMTPDomain[MAX_ADDR_NAME]; char szMessageID[128]; char szMessFilePath[SYS_MAX_PATH]; unsigned long ulMessageOffset; unsigned long ulMailDataOffset; char szSpoolFile[SYS_MAX_PATH]; HSLIST hTagList; unsigned long ulFlags; }; struct MessageTagData { LISTLINK LL; char *pszTagName; char *pszTagData; }; static MessageTagData *USmlAllocTag(char const *pszTagName, char const *pszTagData); static void USmlFreeTag(MessageTagData * pMTD); static MessageTagData *USmlFindTag(HSLIST & hTagList, char const *pszTagName, TAG_POSITION & TagPosition); static int USmlAddTag(HSLIST & hTagList, char const *pszTagName, char const *pszTagData, int iUpdate = 0); static void USmlFreeTagsList(HSLIST & hTagList); static int USmlLoadTags(FILE * pSpoolFile, HSLIST & hTagList); static int USmlDumpHeaders(FILE * pMsgFile, HSLIST & hTagList); static void USmlFreeData(SpoolFileData * pSFD); static void USmlInitHandle(SpoolFileData * pSFD); static SpoolFileData *USmlAllocEmptyHandle(void); static int USmlLoadHandle(SpoolFileData * pSFD, const char *pszMessFilePath); static int USmlFlushMessageFile(SpoolFileData * pSFD); static int USmlGetMailProcessFile(UserInfo * pUI, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char *pszMPFilePath); static int USmlProcessCustomMailingFile(SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char const *pszMPFile, LocalMailProcConfig & LMPC); static int USmlCmdMacroSubstitutes(char **ppszCmdTokens, UserInfo * pUI, SPLF_HANDLE hFSpool); static int USmlCmd_external(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC); static int USmlCmd_filter(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC); static int USmlCmd_mailbox(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC); static int USmlCmd_redirect(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC); static int USmlCmd_lredirect(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC); static int USmlCmd_smtprelay(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC); static int USmlLogMessage(char const *pszSMTPDomain, char const *pszMessageID, char const *pszSmtpMessageID, char const *pszFrom, char const *pszRcpt, char const *pszMedium, char const *pszParam); static int USmlExtractFromAddress(HSLIST & hTagList, char *pszFromAddr, int iMaxAddress); static char const *USmlAddressFromAtPtr(char const *pszAt, char const *pszBase, char *pszAddress, int iMaxAddress); static char const *USmlAddSingleAddress(char const *pszCurr, char const *pszBase, DynString * pAddrDS, char const *const *ppszMatchDomains, int *piAdded); static int USmlAddAddresses(char const *pszAddrList, DynString * pAddrDS, char const *const *ppszMatchDomains); static char **USmlGetAddressList(HSLIST & hTagList, char const *const *ppszMatchDomains, char const *const *ppszAddrTags); static int USmlExtractToAddress(HSLIST & hTagList, char *pszToAddr, int iMaxAddress); static char **USmlBuildTargetRcptList(char const *pszRcptTo, HSLIST & hTagList, const char *pszFetchHdrTags); static int USmlCreateSpoolFile(FILE * pMailFile, char const *const *ppszInfo, char const *pszMailFrom, char const *pszRcptTo, char const *pszSpoolFile); int USmlLoadSpoolFileHeader(char const *pszSpoolFile, SpoolFileHeader & SFH) { ZeroData(SFH); FILE *pSpoolFile = fopen(pszSpoolFile, "rb"); if (pSpoolFile == NULL) { ErrSetErrorCode(ERR_SPOOL_FILE_NOT_FOUND, pszSpoolFile); return (ERR_SPOOL_FILE_NOT_FOUND); } /////////////////////////////////////////////////////////////////////////////// // Build spool file name /////////////////////////////////////////////////////////////////////////////// char szFName[SYS_MAX_PATH] = ""; char szExt[SYS_MAX_PATH] = ""; char szSpoolLine[MAX_SPOOL_LINE] = ""; MscSplitPath(pszSpoolFile, NULL, szFName, szExt); SysSNPrintf(SFH.szSpoolFile, sizeof(SFH.szSpoolFile) - 1, "%s%s", szFName, szExt); /////////////////////////////////////////////////////////////////////////////// // Read info ( 1st row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if ((MscGetString(pSpoolFile, szSpoolLine, sizeof(szSpoolLine) - 1) == NULL) || ((SFH.ppszInfo = StrTokenize(szSpoolLine, ";")) == NULL) || (StrStringsCount(SFH.ppszInfo) < smiMax)) { if (SFH.ppszInfo != NULL) StrFreeStrings(SFH.ppszInfo); fclose(pSpoolFile); ZeroData(SFH); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE, pszSpoolFile); return (ERR_SPOOL_FILE_NOT_FOUND); } /////////////////////////////////////////////////////////////////////////////// // Read SMTP domain ( 2nd row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if (MscGetString(pSpoolFile, SFH.szSMTPDomain, sizeof(SFH.szSMTPDomain) - 1) == NULL) { StrFreeStrings(SFH.ppszInfo); fclose(pSpoolFile); ZeroData(SFH); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE, pszSpoolFile); return (ERR_SPOOL_FILE_NOT_FOUND); } /////////////////////////////////////////////////////////////////////////////// // Read message ID ( 3rd row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if (MscGetString(pSpoolFile, SFH.szMessageID, sizeof(SFH.szMessageID) - 1) == NULL) { StrFreeStrings(SFH.ppszInfo); fclose(pSpoolFile); ZeroData(SFH); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE, pszSpoolFile); return (ERR_SPOOL_FILE_NOT_FOUND); } /////////////////////////////////////////////////////////////////////////////// // Read "MAIL FROM:" ( 4th row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if ((MscGetString(pSpoolFile, szSpoolLine, sizeof(szSpoolLine) - 1) == NULL) || (StrINComp(szSpoolLine, MAIL_FROM_STR) != 0) || ((SFH.ppszFrom = USmtpGetPathStrings(szSpoolLine)) == NULL)) { StrFreeStrings(SFH.ppszInfo); fclose(pSpoolFile); ZeroData(SFH); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE, pszSpoolFile); return (ERR_INVALID_SPOOL_FILE); } /////////////////////////////////////////////////////////////////////////////// // Read "RCPT TO:" ( 5th row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if ((MscGetString(pSpoolFile, szSpoolLine, sizeof(szSpoolLine) - 1) == NULL) || (StrINComp(szSpoolLine, RCPT_TO_STR) != 0) || ((SFH.ppszRcpt = USmtpGetPathStrings(szSpoolLine)) == NULL)) { StrFreeStrings(SFH.ppszFrom); StrFreeStrings(SFH.ppszInfo); fclose(pSpoolFile); ZeroData(SFH); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE, pszSpoolFile); return (ERR_INVALID_SPOOL_FILE); } fclose(pSpoolFile); return (0); } void USmlCleanupSpoolFileHeader(SpoolFileHeader & SFH) { if (SFH.ppszInfo != NULL) StrFreeStrings(SFH.ppszInfo); if (SFH.ppszRcpt != NULL) StrFreeStrings(SFH.ppszRcpt); if (SFH.ppszFrom != NULL) StrFreeStrings(SFH.ppszFrom); ZeroData(SFH); } static MessageTagData *USmlAllocTag(char const *pszTagName, char const *pszTagData) { MessageTagData *pMTD = (MessageTagData *) SysAlloc(sizeof(MessageTagData)); if (pMTD == NULL) return (NULL); ListLinkInit(pMTD); pMTD->pszTagName = SysStrDup(pszTagName); pMTD->pszTagData = SysStrDup(pszTagData); return (pMTD); } static void USmlFreeTag(MessageTagData * pMTD) { SysFree(pMTD->pszTagName); SysFree(pMTD->pszTagData); SysFree(pMTD); } static MessageTagData *USmlFindTag(HSLIST & hTagList, char const *pszTagName, TAG_POSITION & TagPosition) { MessageTagData *pMTD = (TagPosition == TAG_POSITION_INIT) ? (MessageTagData *) ListFirst(hTagList) : (MessageTagData *) TagPosition; for (; pMTD != INVALID_SLIST_PTR; pMTD = (MessageTagData *) ListNext(hTagList, (PLISTLINK) pMTD)) { if (stricmp(pMTD->pszTagName, pszTagName) == 0) { TagPosition = (TAG_POSITION) ListNext(hTagList, (PLISTLINK) pMTD); return (pMTD); } } TagPosition = (TAG_POSITION) INVALID_SLIST_PTR; return (NULL); } static int USmlAddTag(HSLIST & hTagList, char const *pszTagName, char const *pszTagData, int iUpdate) { if (!iUpdate) { MessageTagData *pMTD = USmlAllocTag(pszTagName, pszTagData); if (pMTD == NULL) return (ErrGetErrorCode()); ListAddTail(hTagList, (PLISTLINK) pMTD); } else { TAG_POSITION TagPosition = TAG_POSITION_INIT; MessageTagData *pMTD = USmlFindTag(hTagList, pszTagName, TagPosition); if (pMTD != NULL) { SysFree(pMTD->pszTagData); pMTD->pszTagData = SysStrDup(pszTagData); } else { if ((pMTD = USmlAllocTag(pszTagName, pszTagData)) == NULL) return (ErrGetErrorCode()); ListAddTail(hTagList, (PLISTLINK) pMTD); } } return (0); } static void USmlFreeTagsList(HSLIST & hTagList) { MessageTagData *pMTD; while ((pMTD = (MessageTagData *) ListRemove(hTagList)) != INVALID_SLIST_PTR) USmlFreeTag(pMTD); } static int USmlLoadTags(FILE * pSpoolFile, HSLIST & hTagList) { DynString TagDS; StrDynInit(&TagDS); unsigned long ulFilePos = (unsigned long) ftell(pSpoolFile); char szSpoolLine[MAX_SPOOL_LINE] = ""; char szTagName[256] = ""; while (MscGetString(pSpoolFile, szSpoolLine, sizeof(szSpoolLine) - 1) != NULL) { if (IsEmptyString(szSpoolLine)) { if (StrDynSize(&TagDS) > 0) { if (USmlAddTag(hTagList, szTagName, StrDynGet(&TagDS)) < 0) { ErrorPush(); StrDynFree(&TagDS); fseek(pSpoolFile, ulFilePos, SEEK_SET); return (ErrorPop()); } SetEmptyString(szTagName); StrDynTruncate(&TagDS); } break; } if ((szSpoolLine[0] == ' ') || (szSpoolLine[0] == '\t')) { if (IsEmptyString(szTagName)) { StrDynFree(&TagDS); fseek(pSpoolFile, ulFilePos, SEEK_SET); ErrSetErrorCode(ERR_INVALID_MESSAGE_FORMAT); return (ERR_INVALID_MESSAGE_FORMAT); } if ((StrDynAdd(&TagDS, "\r\n") < 0) || (StrDynAdd(&TagDS, szSpoolLine) < 0)) { ErrorPush(); StrDynFree(&TagDS); fseek(pSpoolFile, ulFilePos, SEEK_SET); return (ErrorPop()); } } else { if (StrDynSize(&TagDS) > 0) { if (USmlAddTag(hTagList, szTagName, StrDynGet(&TagDS)) < 0) { ErrorPush(); StrDynFree(&TagDS); fseek(pSpoolFile, ulFilePos, SEEK_SET); return (ErrorPop()); } SetEmptyString(szTagName); StrDynTruncate(&TagDS); } char *pszEndTag = strchr(szSpoolLine, ':'); if (pszEndTag == NULL) { StrDynFree(&TagDS); fseek(pSpoolFile, ulFilePos, SEEK_SET); ErrSetErrorCode(ERR_INVALID_MESSAGE_FORMAT); return (ERR_INVALID_MESSAGE_FORMAT); } int iNameLength = Min((int) (pszEndTag - szSpoolLine), sizeof(szTagName) - 1); char *pszTagValue = pszEndTag + 1; strncpy(szTagName, szSpoolLine, iNameLength); szTagName[iNameLength] = '\0'; StrSkipSpaces(pszTagValue); if (StrDynAdd(&TagDS, pszTagValue) < 0) { ErrorPush(); StrDynFree(&TagDS); fseek(pSpoolFile, ulFilePos, SEEK_SET); return (ErrorPop()); } } ulFilePos = (unsigned long) ftell(pSpoolFile); } StrDynFree(&TagDS); return (0); } static int USmlDumpHeaders(FILE * pMsgFile, HSLIST & hTagList) { MessageTagData *pMTD = (MessageTagData *) ListFirst(hTagList); for (; pMTD != INVALID_SLIST_PTR; pMTD = (MessageTagData *) ListNext(hTagList, (PLISTLINK) pMTD)) { fprintf(pMsgFile, "%s: %s\r\n", pMTD->pszTagName, pMTD->pszTagData); } return (0); } static void USmlFreeData(SpoolFileData * pSFD) { USmlFreeTagsList(pSFD->hTagList); if (pSFD->ppszInfo != NULL) StrFreeStrings(pSFD->ppszInfo); if (pSFD->ppszFrom != NULL) StrFreeStrings(pSFD->ppszFrom); if (pSFD->pszMailFrom != NULL) SysFree(pSFD->pszMailFrom); if (pSFD->pszSendMailFrom != NULL) SysFree(pSFD->pszSendMailFrom); if (pSFD->ppszRcpt != NULL) StrFreeStrings(pSFD->ppszRcpt); if (pSFD->pszRcptTo != NULL) SysFree(pSFD->pszRcptTo); if (pSFD->pszSendRcptTo != NULL) SysFree(pSFD->pszSendRcptTo); if (pSFD->pszRelayDomain != NULL) SysFree(pSFD->pszRelayDomain); } char *USmlAddrConcat(char const *const *ppszStrings) { int ii; int iStrCount = StrStringsCount(ppszStrings); int iSumLength = 0; for (ii = 0; ii < iStrCount; ii++) iSumLength += strlen(ppszStrings[ii]) + 1; char *pszConcat = (char *) SysAlloc(iSumLength + 1); if (pszConcat == NULL) return (NULL); SetEmptyString(pszConcat); for (ii = 0; ii < iStrCount; ii++) { if (ii > 0) strcat(pszConcat, (ii == (iStrCount - 1)) ? ":" : ","); strcat(pszConcat, ppszStrings[ii]); } return (pszConcat); } char *USmlBuildSendMailFrom(char const *const *ppszFrom, char const *const *ppszRcpt) { int iRcptCount = StrStringsCount(ppszRcpt); int iFromCount = StrStringsCount(ppszFrom); if (iRcptCount == 0) { ErrSetErrorCode(ERR_BAD_FORWARD_PATH); return (NULL); } if (iRcptCount == 1) return (USmlAddrConcat(ppszFrom)); int ii, iSumLength = strlen(ppszRcpt[0]) + 1; for (ii = 0; ii < iFromCount; ii++) iSumLength += strlen(ppszFrom[ii]) + 1; char *pszConcat = (char *) SysAlloc(iSumLength + 1); if (pszConcat == NULL) return (NULL); strcpy(pszConcat, ppszRcpt[0]); for (ii = 0; ii < iFromCount; ii++) { strcat(pszConcat, (ii == (iFromCount - 1)) ? ":" : ","); strcat(pszConcat, ppszFrom[ii]); } return (pszConcat); } char *USmlBuildSendRcptTo(char const *const *ppszFrom, char const *const *ppszRcpt) { int iRcptCount = StrStringsCount(ppszRcpt); int iFromCount = StrStringsCount(ppszFrom); if (iRcptCount == 0) { ErrSetErrorCode(ERR_BAD_FORWARD_PATH); return (NULL); } if (iRcptCount == 1) return (USmlAddrConcat(ppszRcpt)); int ii; int iSumLength = 0; for (ii = 1; ii < iRcptCount; ii++) iSumLength += strlen(ppszRcpt[ii]) + 1; char *pszConcat = (char *) SysAlloc(iSumLength + 1); if (pszConcat == NULL) return (NULL); SetEmptyString(pszConcat); for (ii = 1; ii < iRcptCount; ii++) { if (ii > 1) strcat(pszConcat, (ii == (iRcptCount - 1)) ? ":" : ","); strcat(pszConcat, ppszRcpt[ii]); } return (pszConcat); } static int USmlLoadHandle(SpoolFileData * pSFD, const char *pszMessFilePath) { char szFName[SYS_MAX_PATH] = ""; char szExt[SYS_MAX_PATH] = ""; StrSNCpy(pSFD->szMessFilePath, pszMessFilePath); MscSplitPath(pszMessFilePath, NULL, szFName, szExt); SysSNPrintf(pSFD->szSpoolFile, sizeof(pSFD->szSpoolFile) - 1, "%s%s", szFName, szExt); FILE *pSpoolFile = fopen(pszMessFilePath, "rb"); if (pSpoolFile == NULL) { ErrSetErrorCode(ERR_SPOOL_FILE_NOT_FOUND); return (ERR_SPOOL_FILE_NOT_FOUND); } char szSpoolLine[MAX_SPOOL_LINE] = ""; /////////////////////////////////////////////////////////////////////////////// // Read info ( 1st row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if ((MscGetString(pSpoolFile, szSpoolLine, sizeof(szSpoolLine) - 1) == NULL) || ((pSFD->ppszInfo = StrTokenize(szSpoolLine, ";")) == NULL) || (StrStringsCount(pSFD->ppszInfo) < smiMax)) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } /////////////////////////////////////////////////////////////////////////////// // Read SMTP domain ( 2nd row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if (MscGetString(pSpoolFile, pSFD->szSMTPDomain, sizeof(pSFD->szSMTPDomain) - 1) == NULL) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } /////////////////////////////////////////////////////////////////////////////// // Read message ID ( 3rd row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if (MscGetString(pSpoolFile, pSFD->szMessageID, sizeof(pSFD->szMessageID) - 1) == NULL) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } /////////////////////////////////////////////////////////////////////////////// // Read "MAIL FROM:" ( 4th row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if ((MscGetString(pSpoolFile, szSpoolLine, sizeof(szSpoolLine) - 1) == NULL) || (StrINComp(szSpoolLine, MAIL_FROM_STR) != 0)) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } if ((pSFD->ppszFrom = USmtpGetPathStrings(szSpoolLine)) == NULL) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } /////////////////////////////////////////////////////////////////////////////// // Read "RCPT TO:" ( 5th row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if ((MscGetString(pSpoolFile, szSpoolLine, sizeof(szSpoolLine) - 1) == NULL) || (StrINComp(szSpoolLine, RCPT_TO_STR) != 0)) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } if ((pSFD->ppszRcpt = USmtpGetPathStrings(szSpoolLine)) == NULL) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } /////////////////////////////////////////////////////////////////////////////// // Check the presence of the init data mark ( 5th row of the spool file ) /////////////////////////////////////////////////////////////////////////////// if ((MscGetString(pSpoolFile, szSpoolLine, sizeof(szSpoolLine) - 1) == NULL) || (strncmp(szSpoolLine, SPOOL_FILE_DATA_START, strlen(SPOOL_FILE_DATA_START)) != 0)) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } /////////////////////////////////////////////////////////////////////////////// // Get real message position /////////////////////////////////////////////////////////////////////////////// pSFD->ulMessageOffset = (unsigned long) ftell(pSpoolFile); /////////////////////////////////////////////////////////////////////////////// // Build address strings /////////////////////////////////////////////////////////////////////////////// if (((pSFD->pszMailFrom = USmlAddrConcat(pSFD->ppszFrom)) == NULL) || ((pSFD->pszSendMailFrom = USmlBuildSendMailFrom(pSFD->ppszFrom, pSFD->ppszRcpt)) == NULL) || ((pSFD->pszRcptTo = (char *) USmlAddrConcat(pSFD->ppszRcpt)) == NULL) || ((pSFD->pszSendRcptTo = USmlBuildSendRcptTo(pSFD->ppszFrom, pSFD->ppszRcpt)) == NULL)) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } /////////////////////////////////////////////////////////////////////////////// // Check if it's a relay message /////////////////////////////////////////////////////////////////////////////// if (StrStringsCount(pSFD->ppszRcpt) > 1) { char szRelayDomain[MAX_ADDR_NAME] = ""; if (USmtpSplitEmailAddr(pSFD->ppszRcpt[0], NULL, szRelayDomain) < 0) { fclose(pSpoolFile); ErrSetErrorCode(ERR_INVALID_SPOOL_FILE); return (ERR_INVALID_SPOOL_FILE); } pSFD->pszRelayDomain = SysStrDup(szRelayDomain); } /////////////////////////////////////////////////////////////////////////////// // Load message tags /////////////////////////////////////////////////////////////////////////////// if (USmlLoadTags(pSpoolFile, pSFD->hTagList) < 0) SysLogMessage(LOG_LEV_MESSAGE, "Invalid headers section : %s\n", pSFD->szSpoolFile); /////////////////////////////////////////////////////////////////////////////// // Get spool file position /////////////////////////////////////////////////////////////////////////////// pSFD->ulMailDataOffset = (unsigned long) ftell(pSpoolFile); fclose(pSpoolFile); return (0); } static void USmlInitHandle(SpoolFileData * pSFD) { pSFD->ppszInfo = NULL; pSFD->ppszFrom = NULL; pSFD->pszMailFrom = NULL; pSFD->pszSendMailFrom = NULL; pSFD->ppszRcpt = NULL; pSFD->pszRcptTo = NULL; pSFD->pszSendRcptTo = NULL; pSFD->pszRelayDomain = NULL; SetEmptyString(pSFD->szSMTPDomain); pSFD->ulFlags = 0; ListInit(pSFD->hTagList); } static SpoolFileData *USmlAllocEmptyHandle(void) { /////////////////////////////////////////////////////////////////////////////// // Structure allocation and initialization /////////////////////////////////////////////////////////////////////////////// SpoolFileData *pSFD = (SpoolFileData *) SysAlloc(sizeof(SpoolFileData)); if (pSFD != NULL) USmlInitHandle(pSFD); return (pSFD); } SPLF_HANDLE USmlCreateHandle(const char *pszMessFilePath) { /////////////////////////////////////////////////////////////////////////////// // Structure allocation and initialization /////////////////////////////////////////////////////////////////////////////// SpoolFileData *pSFD = USmlAllocEmptyHandle(); if (pSFD == NULL) return (INVALID_SPLF_HANDLE); if (USmlLoadHandle(pSFD, pszMessFilePath) < 0) { USmlFreeData(pSFD); SysFree(pSFD); return (INVALID_SPLF_HANDLE); } return ((SPLF_HANDLE) pSFD); } void USmlCloseHandle(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; USmlFreeData(pSFD); SysFree(pSFD); } int USmlReloadHandle(SPLF_HANDLE hFSpool) { /////////////////////////////////////////////////////////////////////////////// // Structure allocation and initialization /////////////////////////////////////////////////////////////////////////////// SpoolFileData *pSFD = (SpoolFileData *) hFSpool; SpoolFileData *pNewSFD = USmlAllocEmptyHandle(); if (pNewSFD == NULL) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Load the new spool file data /////////////////////////////////////////////////////////////////////////////// if (USmlLoadHandle(pNewSFD, pSFD->szMessFilePath) < 0) { ErrorPush(); USmlFreeData(pNewSFD); SysFree(pNewSFD); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Free the original structure data and load the new one /////////////////////////////////////////////////////////////////////////////// USmlFreeData(pSFD); *pSFD = *pNewSFD; /////////////////////////////////////////////////////////////////////////////// // We don't have to call USmlFreeData() since its content has been tranfered // to the original structure to replace the old information /////////////////////////////////////////////////////////////////////////////// SysFree(pNewSFD); return (0); } char const *USmlGetRelayDomain(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->pszRelayDomain); } char const *USmlGetSpoolFilePath(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->szMessFilePath); } char const *USmlGetSpoolFile(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->szSpoolFile); } char const *USmlGetSMTPDomain(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->szSMTPDomain); } char const *USmlGetSmtpMessageID(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->szMessageID); } char const *const *USmlGetInfo(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->ppszInfo); } char const *const *USmlGetMailFrom(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->ppszFrom); } char const *USmlMailFrom(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->pszMailFrom); } char const *USmlSendMailFrom(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->pszSendMailFrom); } char const *const *USmlGetRcptTo(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->ppszRcpt); } char const *USmlRcptTo(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->pszRcptTo); } char const *USmlSendRcptTo(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; return (pSFD->pszSendRcptTo); } static int USmlFlushMessageFile(SpoolFileData * pSFD) { char szTmpMsgFile[SYS_MAX_PATH] = ""; SysSNPrintf(szTmpMsgFile, sizeof(szTmpMsgFile) - 1, "%s.flush", pSFD->szMessFilePath); /////////////////////////////////////////////////////////////////////////////// // Create temporary file /////////////////////////////////////////////////////////////////////////////// FILE *pMsgFile = fopen(szTmpMsgFile, "wb"); if (pMsgFile == NULL) { ErrSetErrorCode(ERR_FILE_CREATE, szTmpMsgFile); return (ERR_FILE_CREATE); } /////////////////////////////////////////////////////////////////////////////// // Open message file /////////////////////////////////////////////////////////////////////////////// FILE *pMessFile = fopen(pSFD->szMessFilePath, "rb"); if (pMessFile == NULL) { fclose(pMsgFile); CheckRemoveFile(szTmpMsgFile); ErrSetErrorCode(ERR_FILE_OPEN, pSFD->szMessFilePath); return (ERR_FILE_OPEN); } /////////////////////////////////////////////////////////////////////////////// // Dump info section ( start = 0 - bytes = ulMessageOffset ) /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(pMsgFile, pMessFile, 0, pSFD->ulMessageOffset) < 0) { ErrorPush(); fclose(pMessFile); fclose(pMsgFile); CheckRemoveFile(szTmpMsgFile); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Dump message headers /////////////////////////////////////////////////////////////////////////////// if (USmlDumpHeaders(pMsgFile, pSFD->hTagList) < 0) { ErrorPush(); fclose(pMessFile); fclose(pMsgFile); CheckRemoveFile(szTmpMsgFile); return (ErrorPop()); } fprintf(pMsgFile, "\r\n"); /////////////////////////////////////////////////////////////////////////////// // Get the new message body offset /////////////////////////////////////////////////////////////////////////////// unsigned long ulMailDataOffset = (unsigned long) ftell(pMsgFile); /////////////////////////////////////////////////////////////////////////////// // Dump message data ( start = ulMailDataOffset - bytes = -1 [EOF] ) /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(pMsgFile, pMessFile, pSFD->ulMailDataOffset, (unsigned long) -1) < 0) { ErrorPush(); fclose(pMessFile); fclose(pMsgFile); CheckRemoveFile(szTmpMsgFile); return (ErrorPop()); } fclose(pMessFile); if (SysFileSync(pMsgFile) < 0) { ErrorPush(); fclose(pMsgFile); CheckRemoveFile(szTmpMsgFile); return (ErrorPop()); } if (fclose(pMsgFile)) { CheckRemoveFile(szTmpMsgFile); ErrSetErrorCode(ERR_FILE_WRITE, szTmpMsgFile); return (ERR_FILE_WRITE); } /////////////////////////////////////////////////////////////////////////////// // Move the file /////////////////////////////////////////////////////////////////////////////// if ((SysRemove(pSFD->szMessFilePath) < 0) || (SysMoveFile(szTmpMsgFile, pSFD->szMessFilePath) < 0)) { ErrorPush(); CheckRemoveFile(szTmpMsgFile); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Set the new message body offset /////////////////////////////////////////////////////////////////////////////// pSFD->ulMailDataOffset = ulMailDataOffset; return (0); } int USmlSyncChanges(SPLF_HANDLE hFSpool) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; if (pSFD->ulFlags & SFF_HEADER_MODIFIED) { if (USmlFlushMessageFile(pSFD) == 0) pSFD->ulFlags &= ~SFF_HEADER_MODIFIED; } return (0); } int USmlGetMsgFileSection(SPLF_HANDLE hFSpool, FileSection & FS) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; /////////////////////////////////////////////////////////////////////////////// // Sync message file /////////////////////////////////////////////////////////////////////////////// if (USmlSyncChanges(hFSpool) < 0) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Setup file section fields /////////////////////////////////////////////////////////////////////////////// ZeroData(FS); StrSNCpy(FS.szFilePath, pSFD->szMessFilePath); FS.ulStartOffset = pSFD->ulMessageOffset; FS.ulEndOffset = (unsigned long) -1; return (0); } int USmlWriteMailFile(SPLF_HANDLE hFSpool, FILE * pMsgFile) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; /////////////////////////////////////////////////////////////////////////////// // Dump message tags /////////////////////////////////////////////////////////////////////////////// if (USmlDumpHeaders(pMsgFile, pSFD->hTagList) < 0) return (ErrGetErrorCode()); fprintf(pMsgFile, "\r\n"); /////////////////////////////////////////////////////////////////////////////// // Dump message data /////////////////////////////////////////////////////////////////////////////// FILE *pMessFile = fopen(pSFD->szMessFilePath, "rb"); if (pMessFile == NULL) { ErrSetErrorCode(ERR_FILE_OPEN, pSFD->szMessFilePath); return (ERR_FILE_OPEN); } if (MscCopyFile(pMsgFile, pMessFile, pSFD->ulMailDataOffset, (unsigned long) -1) < 0) { ErrorPush(); fclose(pMessFile); return (ErrorPop()); } fclose(pMessFile); return (0); } char *USmlGetTag(SPLF_HANDLE hFSpool, char const *pszTagName, TAG_POSITION & TagPosition) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; MessageTagData *pMTD = USmlFindTag(pSFD->hTagList, pszTagName, TagPosition); return ((pMTD != NULL) ? SysStrDup(pMTD->pszTagData) : NULL); } int USmlAddTag(SPLF_HANDLE hFSpool, char const *pszTagName, char const *pszTagData, int iUpdate) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; if (USmlAddTag(pSFD->hTagList, pszTagName, pszTagData, iUpdate) < 0) return (ErrGetErrorCode()); pSFD->ulFlags |= SFF_HEADER_MODIFIED; return (0); } int USmlSetTagAddress(SPLF_HANDLE hFSpool, char const *pszTagName, char const *pszAddress) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; TAG_POSITION TagPosition = TAG_POSITION_INIT; char *pszOldAddress = USmlGetTag(hFSpool, pszTagName, TagPosition); if (pszOldAddress == NULL) { char szTagData[512] = ""; SysSNPrintf(szTagData, sizeof(szTagData) - 1, "<%s>", pszAddress); if (USmlAddTag(pSFD->hTagList, pszTagName, szTagData, 1) < 0) return (ErrGetErrorCode()); } else { char *pszOpen = strrchr(pszOldAddress, '<'); if (pszOpen != NULL) { /////////////////////////////////////////////////////////////////////////////// // Case : NAME <ADDRESS> /////////////////////////////////////////////////////////////////////////////// char *pszClose = strrchr(pszOpen + 1, '>'); if (pszClose == NULL) { SysFree(pszOldAddress); ErrSetErrorCode(ERR_INVALID_MESSAGE_FORMAT); return (ERR_INVALID_MESSAGE_FORMAT); } DynString DS; StrDynInit(&DS); StrDynAdd(&DS, pszOldAddress, (int) (pszOpen - pszOldAddress) + 1); StrDynAdd(&DS, pszAddress); StrDynAdd(&DS, pszClose); SysFree(pszOldAddress); if (USmlAddTag(pSFD->hTagList, pszTagName, StrDynGet(&DS), 1) < 0) { ErrorPush(); StrDynFree(&DS); return (ErrorPop()); } StrDynFree(&DS); } else { /////////////////////////////////////////////////////////////////////////////// // Case : ADDRESS /////////////////////////////////////////////////////////////////////////////// SysFree(pszOldAddress); if (USmlAddTag(pSFD->hTagList, pszTagName, pszAddress, 1) < 0) return (ErrGetErrorCode()); } } return (0); } int USmlMapAddress(char const *pszAddress, char *pszDomain, char *pszName) { char szRmtDomain[MAX_ADDR_NAME] = ""; char szRmtName[MAX_ADDR_NAME] = ""; if (USmtpSplitEmailAddr(pszAddress, szRmtName, szRmtDomain) < 0) return (ErrGetErrorCode()); ExtAlias *pExtAlias = ExAlGetAlias(szRmtDomain, szRmtName); if (pExtAlias == NULL) return (ErrGetErrorCode()); strcpy(pszDomain, pExtAlias->pszDomain); strcpy(pszName, pExtAlias->pszName); ExAlFreeAlias(pExtAlias); return (0); } int USmlCreateMBFile(UserInfo * pUI, char const *pszFileName, SPLF_HANDLE hFSpool) { char const *const *ppszFrom = USmlGetMailFrom(hFSpool); FILE *pMBFile = fopen(pszFileName, "wb"); if (pMBFile == NULL) { ErrSetErrorCode(ERR_FILE_CREATE, pszFileName); return (ERR_FILE_CREATE); } /////////////////////////////////////////////////////////////////////////////// // Check the existence of the return path string ( PSYNC messages have ) /////////////////////////////////////////////////////////////////////////////// TAG_POSITION TagPosition = TAG_POSITION_INIT; char *pszReturnPath = USmlGetTag(hFSpool, "Return-Path", TagPosition); if (pszReturnPath == NULL) { /////////////////////////////////////////////////////////////////////////////// // Build return path string /////////////////////////////////////////////////////////////////////////////// int iFromDomains = StrStringsCount(ppszFrom); char szDomain[MAX_ADDR_NAME] = ""; char szName[MAX_ADDR_NAME] = ""; char szReturnPath[1024] = "Return-Path: <>"; if ((iFromDomains == 0) || (USmlMapAddress(ppszFrom[iFromDomains - 1], szDomain, szName) < 0)) { char *pszRetPath = USmlAddrConcat(ppszFrom); if (pszRetPath != NULL) { int iRetLength = strlen(pszRetPath); int iExtraLength = CStringSize("Return-Path: <>"); if (iRetLength > (int) (sizeof(szReturnPath) - iExtraLength - 2)) pszRetPath[sizeof(szReturnPath) - iExtraLength - 2] = '\0'; SysSNPrintf(szReturnPath, sizeof(szReturnPath) - 1, "Return-Path: <%s>", pszRetPath); SysFree(pszRetPath); } } else { SysSNPrintf(szReturnPath, sizeof(szReturnPath) - 1, "Return-Path: <%s@%s>", szName, szDomain); char szAddress[MAX_ADDR_NAME] = ""; SysSNPrintf(szAddress, sizeof(szAddress) - 1, "%s@%s", szName, szDomain); USmlSetTagAddress(hFSpool, "Reply-To", szAddress); } fprintf(pMBFile, "%s\r\n", szReturnPath); /////////////////////////////////////////////////////////////////////////////// // Add "Delivered-To:" tag /////////////////////////////////////////////////////////////////////////////// char szUserAddress[MAX_ADDR_NAME] = ""; UsrGetAddress(pUI, szUserAddress); fprintf(pMBFile, "Delivered-To: %s\r\n", szUserAddress); } else SysFree(pszReturnPath); /////////////////////////////////////////////////////////////////////////////// // Write mail file /////////////////////////////////////////////////////////////////////////////// if (USmlWriteMailFile(hFSpool, pMBFile) < 0) { ErrorPush(); fclose(pMBFile); SysRemove(pszFileName); return (ErrorPop()); } fclose(pMBFile); return (0); } int USmlVCreateSpoolFile(SPLF_HANDLE hFSpool, char const *pszFromUser, char const *pszRcptUser, char const *pszFileName, va_list Headers) { char const *pszSMTPDomain = USmlGetSMTPDomain(hFSpool); char const *pszSmtpMessageID = USmlGetSmtpMessageID(hFSpool); char const *const *ppszInfo = USmlGetInfo(hFSpool); char const *const *ppszFrom = USmlGetMailFrom(hFSpool); char const *const *ppszRcpt = USmlGetRcptTo(hFSpool); FILE *pSpoolFile = fopen(pszFileName, "wb"); if (pSpoolFile == NULL) { ErrSetErrorCode(ERR_FILE_CREATE); return (ERR_FILE_CREATE); } /////////////////////////////////////////////////////////////////////////////// // Write info line /////////////////////////////////////////////////////////////////////////////// USmtpWriteInfoLine(pSpoolFile, ppszInfo[smiClientAddr], ppszInfo[smiServerAddr], ppszInfo[smiTime]); /////////////////////////////////////////////////////////////////////////////// // Write SMTP domain /////////////////////////////////////////////////////////////////////////////// fprintf(pSpoolFile, "%s\r\n", pszSMTPDomain); /////////////////////////////////////////////////////////////////////////////// // Write message ID /////////////////////////////////////////////////////////////////////////////// fprintf(pSpoolFile, "%s\r\n", pszSmtpMessageID); /////////////////////////////////////////////////////////////////////////////// // Write "MAIL FROM:" /////////////////////////////////////////////////////////////////////////////// char const *pszMailFrom = USmlMailFrom(hFSpool); fprintf(pSpoolFile, "MAIL FROM: <%s>\r\n", (pszFromUser != NULL) ? pszFromUser : pszMailFrom); /////////////////////////////////////////////////////////////////////////////// // Write "RCPT TO:" /////////////////////////////////////////////////////////////////////////////// char const *pszRcptTo = USmlRcptTo(hFSpool); fprintf(pSpoolFile, "RCPT TO: <%s>\r\n", (pszRcptUser != NULL) ? pszRcptUser : pszRcptTo); /////////////////////////////////////////////////////////////////////////////// // Write SPOOL_FILE_DATA_START /////////////////////////////////////////////////////////////////////////////// fprintf(pSpoolFile, "%s\r\n", SPOOL_FILE_DATA_START); /////////////////////////////////////////////////////////////////////////////// // Write extra RFC822 headers /////////////////////////////////////////////////////////////////////////////// char const *pszHeader = NULL; while ((pszHeader = va_arg(Headers, char *)) != NULL) { char const *pszValue = va_arg(Headers, char *); if (pszValue == NULL) break; if (!IsEmptyString(pszHeader)) fprintf(pSpoolFile, "%s: %s\r\n", pszHeader, pszValue); } /////////////////////////////////////////////////////////////////////////////// // Than write mail data /////////////////////////////////////////////////////////////////////////////// if (USmlWriteMailFile(hFSpool, pSpoolFile) < 0) { ErrorPush(); fclose(pSpoolFile); SysRemove(pszFileName); return (ErrorPop()); } fclose(pSpoolFile); return (0); } int USmlCreateSpoolFile(SPLF_HANDLE hFSpool, char const *pszFromUser, char const *pszRcptUser, char const *pszFileName, ...) { va_list Headers; va_start(Headers, pszFileName); int iCreateResult = USmlVCreateSpoolFile(hFSpool, pszFromUser, pszRcptUser, pszFileName, Headers); va_end(Headers); return (iCreateResult); } static int USmlGetMailProcessFile(UserInfo * pUI, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char *pszMPFilePath) { /////////////////////////////////////////////////////////////////////////////// // Get the custom spool file associated with this message /////////////////////////////////////////////////////////////////////////////// if (USmlGetUserCustomSpoolFile(hQueue, hMessage, pszMPFilePath) < 0) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // If the file already exist inside the spool, just return the latest /////////////////////////////////////////////////////////////////////////////// if (SysExistFile(pszMPFilePath)) return (0); /////////////////////////////////////////////////////////////////////////////// // Try to get a new copy from the user one. It'll fail if the account is not // handled with a custom mail processing /////////////////////////////////////////////////////////////////////////////// return (UsrGetMailProcessFile(pUI, pszMPFilePath)); } int USmlProcessLocalUserMessage(SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC) { /////////////////////////////////////////////////////////////////////////////// // Exist user custom message processing ? /////////////////////////////////////////////////////////////////////////////// char szMPFile[SYS_MAX_PATH] = ""; if (USmlGetMailProcessFile(pUI, hQueue, hMessage, szMPFile) < 0) { /////////////////////////////////////////////////////////////////////////////// // Apply filters ... /////////////////////////////////////////////////////////////////////////////// if (FilFilterMessage(hFSpool, hQueue, hMessage, FILTER_MODE_INBOUND) < 0) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Create mailbox file ... /////////////////////////////////////////////////////////////////////////////// char szMBFile[SYS_MAX_PATH] = ""; SysGetTmpFile(szMBFile); if (USmlCreateMBFile(pUI, szMBFile, hFSpool) < 0) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // and send it home /////////////////////////////////////////////////////////////////////////////// char const *pszMessageID = USmlGetSpoolFile(hFSpool); if (UsrMoveToMailBox(pUI, szMBFile, pszMessageID) < 0) { ErrorPush(); SysRemove(szMBFile); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Log operation /////////////////////////////////////////////////////////////////////////////// if (LMPC.ulFlags & LMPCF_LOG_ENABLED) { char szLocalAddress[MAX_ADDR_NAME] = ""; USmlLogMessage(hFSpool, "LOCAL", UsrGetAddress(pUI, szLocalAddress)); } } else { /////////////////////////////////////////////////////////////////////////////// // Process custom mailings /////////////////////////////////////////////////////////////////////////////// if (USmlProcessCustomMailingFile(hSvrConfig, pUI, hFSpool, hQueue, hMessage, szMPFile, LMPC) < 0) return (ErrGetErrorCode()); } return (0); } static int USmlProcessCustomMailingFile(SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char const *pszMPFile, LocalMailProcConfig & LMPC) { /////////////////////////////////////////////////////////////////////////////// // Open the mail processing file /////////////////////////////////////////////////////////////////////////////// FILE *pMPFile = fopen(pszMPFile, "rt"); if (pMPFile == NULL) { ErrSetErrorCode(ERR_FILE_OPEN, pszMPFile); return (ERR_FILE_OPEN); } /////////////////////////////////////////////////////////////////////////////// // Create pushback command file /////////////////////////////////////////////////////////////////////////////// char szTmpFile[SYS_MAX_PATH] = ""; SysGetTmpFile(szTmpFile); FILE *pPushBFile = fopen(szTmpFile, "wt"); if (pPushBFile == NULL) { fclose(pMPFile); ErrSetErrorCode(ERR_FILE_CREATE, szTmpFile); return (ERR_FILE_CREATE); } int iPushBackCmds = 0; char szCmdLine[CUSTOM_CMD_LINE_MAX] = ""; while (MscGetConfigLine(szCmdLine, sizeof(szCmdLine) - 1, pMPFile) != NULL) { char **ppszCmdTokens = StrGetTabLineStrings(szCmdLine); if (ppszCmdTokens == NULL) continue; int iFieldsCount = StrStringsCount(ppszCmdTokens); if (iFieldsCount > 0) { /////////////////////////////////////////////////////////////////////////////// // Do command line macro substitution /////////////////////////////////////////////////////////////////////////////// USmlCmdMacroSubstitutes(ppszCmdTokens, pUI, hFSpool); int iCmdResult = 0; if (stricmp(ppszCmdTokens[0], "external") == 0) iCmdResult = USmlCmd_external(ppszCmdTokens, iFieldsCount, hSvrConfig, pUI, hFSpool, hQueue, hMessage, LMPC); else if (stricmp(ppszCmdTokens[0], "filter") == 0) iCmdResult = USmlCmd_filter(ppszCmdTokens, iFieldsCount, hSvrConfig, pUI, hFSpool, hQueue, hMessage, LMPC); else if (stricmp(ppszCmdTokens[0], "mailbox") == 0) iCmdResult = USmlCmd_mailbox(ppszCmdTokens, iFieldsCount, hSvrConfig, pUI, hFSpool, hQueue, hMessage, LMPC); else if (stricmp(ppszCmdTokens[0], "redirect") == 0) iCmdResult = USmlCmd_redirect(ppszCmdTokens, iFieldsCount, hSvrConfig, pUI, hFSpool, hQueue, hMessage, LMPC); else if (stricmp(ppszCmdTokens[0], "lredirect") == 0) iCmdResult = USmlCmd_lredirect(ppszCmdTokens, iFieldsCount, hSvrConfig, pUI, hFSpool, hQueue, hMessage, LMPC); else if (stricmp(ppszCmdTokens[0], "smtprelay") == 0) iCmdResult = USmlCmd_smtprelay(ppszCmdTokens, iFieldsCount, hSvrConfig, pUI, hFSpool, hQueue, hMessage, LMPC); else { SysLogMessage(LOG_LEV_ERROR, "Invalid command \"%s\" in file \"%s\"\n", ppszCmdTokens[0], pszMPFile); } /////////////////////////////////////////////////////////////////////////////// // Check for the stop-processing error code /////////////////////////////////////////////////////////////////////////////// if (iCmdResult == SMAIL_STOP_PROCESSING) { StrFreeStrings(ppszCmdTokens); break; } /////////////////////////////////////////////////////////////////////////////// // Test if we must save a failed command // <0 = Error ; ==0 = Success ; >0 = Transient error ( save the command ) /////////////////////////////////////////////////////////////////////////////// if (iCmdResult > 0) { fprintf(pPushBFile, "%s\n", szCmdLine); ++iPushBackCmds; } /////////////////////////////////////////////////////////////////////////////// // An error code might result if filters blocked the message. If this is the // case QueCheckMessage() will return error and we MUST stop processing /////////////////////////////////////////////////////////////////////////////// if ((iCmdResult < 0) && (QueCheckMessage(hQueue, hMessage) < 0)) { ErrorPush(); StrFreeStrings(ppszCmdTokens); fclose(pPushBFile); fclose(pMPFile); SysRemove(szTmpFile); return (ErrorPop()); } } StrFreeStrings(ppszCmdTokens); } fclose(pPushBFile); fclose(pMPFile); SysRemove(pszMPFile); if (iPushBackCmds > 0) { /////////////////////////////////////////////////////////////////////////////// // If commands left out of processing, push them into the custom file /////////////////////////////////////////////////////////////////////////////// if (MscMoveFile(szTmpFile, pszMPFile) < 0) return (ErrGetErrorCode()); ErrSetErrorCode(ERR_INCOMPLETE_PROCESSING); return (ERR_INCOMPLETE_PROCESSING); } SysRemove(szTmpFile); return (0); } static int USmlCmdMacroSubstitutes(char **ppszCmdTokens, UserInfo * pUI, SPLF_HANDLE hFSpool) { char const *pszSMTPDomain = USmlGetSMTPDomain(hFSpool); char const *const *ppszFrom = USmlGetMailFrom(hFSpool); char const *const *ppszRcpt = USmlGetRcptTo(hFSpool); char const *pszSmtpMessageID = USmlGetSmtpMessageID(hFSpool); char const *pszMessageID = USmlGetSpoolFile(hFSpool); int iFromDomains = StrStringsCount(ppszFrom); int iRcptDomains = StrStringsCount(ppszRcpt); FileSection FS; /////////////////////////////////////////////////////////////////////////////// // This function retrieve the spool file message section and sync the content. // This is necessary before passing the file name to external commands. /////////////////////////////////////////////////////////////////////////////// if (USmlGetMsgFileSection(hFSpool, FS) < 0) return (ErrGetErrorCode()); for (int ii = 0; ppszCmdTokens[ii] != NULL; ii++) { if (strcmp(ppszCmdTokens[ii], "@@FROM") == 0) { char *pszNewValue = SysStrDup((iFromDomains > 0) ? ppszFrom[iFromDomains - 1] : ""); if (pszNewValue == NULL) return (ErrGetErrorCode()); SysFree(ppszCmdTokens[ii]); ppszCmdTokens[ii] = pszNewValue; } else if (strcmp(ppszCmdTokens[ii], "@@RCPT") == 0) { char *pszNewValue = SysStrDup((iRcptDomains > 0) ? ppszRcpt[iRcptDomains - 1] : ""); if (pszNewValue == NULL) return (ErrGetErrorCode()); SysFree(ppszCmdTokens[ii]); ppszCmdTokens[ii] = pszNewValue; } else if (strcmp(ppszCmdTokens[ii], "@@RRCPT") == 0) { char szUserAddress[MAX_ADDR_NAME] = ""; UsrGetAddress(pUI, szUserAddress); char *pszNewValue = SysStrDup(szUserAddress); if (pszNewValue == NULL) return (ErrGetErrorCode()); SysFree(ppszCmdTokens[ii]); ppszCmdTokens[ii] = pszNewValue; } else if (strcmp(ppszCmdTokens[ii], "@@FILE") == 0) { char *pszNewValue = SysStrDup(FS.szFilePath); if (pszNewValue == NULL) return (ErrGetErrorCode()); SysFree(ppszCmdTokens[ii]); ppszCmdTokens[ii] = pszNewValue; } else if (strcmp(ppszCmdTokens[ii], "@@MSGID") == 0) { char *pszNewValue = SysStrDup(pszMessageID); if (pszNewValue == NULL) return (ErrGetErrorCode()); SysFree(ppszCmdTokens[ii]); ppszCmdTokens[ii] = pszNewValue; } else if (strcmp(ppszCmdTokens[ii], "@@MSGREF") == 0) { char *pszNewValue = SysStrDup(pszSmtpMessageID); if (pszNewValue == NULL) return (ErrGetErrorCode()); SysFree(ppszCmdTokens[ii]); ppszCmdTokens[ii] = pszNewValue; } else if (strcmp(ppszCmdTokens[ii], "@@TMPFILE") == 0) { char szTmpFile[SYS_MAX_PATH] = ""; SysGetTmpFile(szTmpFile); if (MscCopyFile(szTmpFile, FS.szFilePath) < 0) { ErrorPush(); CheckRemoveFile(szTmpFile); return (ErrorPop()); } char *pszNewValue = SysStrDup(szTmpFile); if (pszNewValue == NULL) return (ErrGetErrorCode()); SysFree(ppszCmdTokens[ii]); ppszCmdTokens[ii] = pszNewValue; } } return (0); } static int USmlCmd_external(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC) { /////////////////////////////////////////////////////////////////////////////// // Apply filters ... /////////////////////////////////////////////////////////////////////////////// if (FilFilterMessage(hFSpool, hQueue, hMessage, FILTER_MODE_INBOUND) < 0) return (ErrGetErrorCode()); if (iNumTokens < 5) { ErrSetErrorCode(ERR_BAD_MAILPROC_CMD_SYNTAX); return (ERR_BAD_MAILPROC_CMD_SYNTAX); } int iPriority = atoi(ppszCmdTokens[1]); int iWaitTimeout = atoi(ppszCmdTokens[2]); int iExitStatus = 0; if (SysExec(ppszCmdTokens[3], &ppszCmdTokens[3], iWaitTimeout, iPriority, &iExitStatus) < 0) { ErrorPush(); char const *pszMailFrom = USmlMailFrom(hFSpool); char const *pszRcptTo = USmlRcptTo(hFSpool); ErrLogMessage(LOG_LEV_MESSAGE, "USMAIL EXTRN-Send Prg = \"%s\" From = \"%s\" To = \"%s\" Failed !\n", ppszCmdTokens[3], pszMailFrom, pszRcptTo); QueUtErrLogMessage(hQueue, hMessage, "USMAIL EXTRN-Send Prg = \"%s\" From = \"%s\" To = \"%s\" Failed !\n", ppszCmdTokens[3], pszMailFrom, pszRcptTo); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Log operation /////////////////////////////////////////////////////////////////////////////// if (LMPC.ulFlags & LMPCF_LOG_ENABLED) USmlLogMessage(hFSpool, "EXTRN", ppszCmdTokens[3]); return ((iExitStatus == SMAIL_EXTERNAL_EXIT_BREAK) ? SMAIL_STOP_PROCESSING: 0); } static int USmlCmd_filter(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC) { if (iNumTokens < 5) { ErrSetErrorCode(ERR_BAD_MAILPROC_CMD_SYNTAX); return (ERR_BAD_MAILPROC_CMD_SYNTAX); } int iPriority = atoi(ppszCmdTokens[1]); int iWaitTimeout = atoi(ppszCmdTokens[2]); int iExitStatus = 0; if (SysExec(ppszCmdTokens[3], &ppszCmdTokens[3], iWaitTimeout, iPriority, &iExitStatus) < 0) { ErrorPush(); char const *pszMailFrom = USmlMailFrom(hFSpool); char const *pszRcptTo = USmlRcptTo(hFSpool); ErrLogMessage(LOG_LEV_MESSAGE, "USMAIL FILTER Prg = \"%s\" From = \"%s\" To = \"%s\" Failed !\n", ppszCmdTokens[3], pszMailFrom, pszRcptTo); QueUtErrLogMessage(hQueue, hMessage, "USMAIL FILTER Prg = \"%s\" From = \"%s\" To = \"%s\" Failed !\n", ppszCmdTokens[3], pszMailFrom, pszRcptTo); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Log operation /////////////////////////////////////////////////////////////////////////////// if (LMPC.ulFlags & LMPCF_LOG_ENABLED) USmlLogMessage(hFSpool, "FILTER", ppszCmdTokens[3]); /////////////////////////////////////////////////////////////////////////////// // Separate code from flags /////////////////////////////////////////////////////////////////////////////// int iExitFlags = iExitStatus & FILTER_FLAGS_MASK; iExitStatus &= ~FILTER_FLAGS_MASK; if ((iExitStatus == FILTER_OUT_EXITCODE) || (iExitStatus == FILTER_OUT_NN_EXITCODE) || (iExitStatus == FILTER_OUT_NNF_EXITCODE)) { /////////////////////////////////////////////////////////////////////////////// // Filter out message /////////////////////////////////////////////////////////////////////////////// char *pszRejMsg = FilGetFilterRejMessage(USmlGetSpoolFilePath(hFSpool)); if (iExitStatus == FILTER_OUT_EXITCODE) QueUtNotifyPermErrDelivery(hQueue, hMessage, NULL, (pszRejMsg != NULL) ? pszRejMsg : ErrGetErrorString(ERR_FILTERED_MESSAGE), NULL, true); else if (iExitStatus == FILTER_OUT_NN_EXITCODE) QueCleanupMessage(hQueue, hMessage, !QueUtRemoveSpoolErrors()); else QueCleanupMessage(hQueue, hMessage, false); if (pszRejMsg != NULL) SysFree(pszRejMsg); ErrSetErrorCode(ERR_FILTERED_MESSAGE); return (ERR_FILTERED_MESSAGE); } else if (iExitStatus == FILTER_MODIFY_EXITCODE) { /////////////////////////////////////////////////////////////////////////////// // Filter modified the message, we need to reload the spool handle /////////////////////////////////////////////////////////////////////////////// if (USmlReloadHandle(hFSpool) < 0) { ErrorPush(); char const *pszMailFrom = USmlMailFrom(hFSpool); char const *pszRcptTo = USmlRcptTo(hFSpool); SysLogMessage(LOG_LEV_MESSAGE, "Filter error [ Modified message corrupted ]: Sender = \"%s\" Recipient = \"%s\" (%s)\n", pszMailFrom, pszRcptTo, ppszCmdTokens[3]); QueUtErrLogMessage(hQueue, hMessage, "Filter error [ Modified message corrupted ]: Sender = \"%s\" Recipient = \"%s\" (%s)\n", pszMailFrom, pszRcptTo, ppszCmdTokens[3]); QueCleanupMessage(hQueue, hMessage, true); return (ErrorPop()); } } return ((iExitFlags & FILTER_FLAGS_BREAK) ? SMAIL_STOP_PROCESSING: 0); } static int USmlCmd_mailbox(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC) { /////////////////////////////////////////////////////////////////////////////// // Apply filters ... /////////////////////////////////////////////////////////////////////////////// if (FilFilterMessage(hFSpool, hQueue, hMessage, FILTER_MODE_INBOUND) < 0) return (ErrGetErrorCode()); if (iNumTokens != 1) { ErrSetErrorCode(ERR_BAD_MAILPROC_CMD_SYNTAX); return (ERR_BAD_MAILPROC_CMD_SYNTAX); } /////////////////////////////////////////////////////////////////////////////// // Create mailbox file ... /////////////////////////////////////////////////////////////////////////////// char szMBFile[SYS_MAX_PATH] = ""; SysGetTmpFile(szMBFile); if (USmlCreateMBFile(pUI, szMBFile, hFSpool) < 0) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // and send it home /////////////////////////////////////////////////////////////////////////////// char const *pszMessageID = USmlGetSpoolFile(hFSpool); if (UsrMoveToMailBox(pUI, szMBFile, pszMessageID) < 0) { ErrorPush(); SysRemove(szMBFile); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Log operation /////////////////////////////////////////////////////////////////////////////// if (LMPC.ulFlags & LMPCF_LOG_ENABLED) { char szLocalAddress[MAX_ADDR_NAME] = ""; USmlLogMessage(hFSpool, "LOCAL", UsrGetAddress(pUI, szLocalAddress)); } return (0); } static int USmlCmd_redirect(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC) { if (iNumTokens < 2) { ErrSetErrorCode(ERR_BAD_MAILPROC_CMD_SYNTAX); return (ERR_BAD_MAILPROC_CMD_SYNTAX); } char szUserAddress[MAX_ADDR_NAME] = ""; UsrGetAddress(pUI, szUserAddress); /////////////////////////////////////////////////////////////////////////////// // Redirection loop /////////////////////////////////////////////////////////////////////////////// char const *pszSMTPDomain = USmlGetSMTPDomain(hFSpool); for (int ii = 1; ppszCmdTokens[ii] != NULL; ii++) { /////////////////////////////////////////////////////////////////////////////// // Get message handle /////////////////////////////////////////////////////////////////////////////// QMSG_HANDLE hRedirMessage = QueCreateMessage(hSpoolQueue); if (hRedirMessage == INVALID_QMSG_HANDLE) return (ErrGetErrorCode()); char szQueueFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hSpoolQueue, hRedirMessage, szQueueFilePath); char szAliasAddr[MAX_ADDR_NAME] = ""; if (strchr(ppszCmdTokens[ii], '@') == NULL) SysSNPrintf(szAliasAddr, sizeof(szAliasAddr) - 1, "%s@%s", pUI->pszName, ppszCmdTokens[ii]); else StrSNCpy(szAliasAddr, ppszCmdTokens[ii]); if (USmlCreateSpoolFile(hFSpool, NULL, szAliasAddr, szQueueFilePath, "X-Deliver-To", szUserAddress, NULL) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hRedirMessage); QueCloseMessage(hSpoolQueue, hRedirMessage); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Transfer file to the spool /////////////////////////////////////////////////////////////////////////////// if (QueCommitMessage(hSpoolQueue, hRedirMessage) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hRedirMessage); QueCloseMessage(hSpoolQueue, hRedirMessage); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Log the redir operation /////////////////////////////////////////////////////////////////////////////// if (LMPC.ulFlags & LMPCF_LOG_ENABLED) USmlLogMessage(hFSpool, "REDIR", ppszCmdTokens[ii]); } return (0); } static int USmlCmd_lredirect(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC) { if (iNumTokens < 2) { ErrSetErrorCode(ERR_BAD_MAILPROC_CMD_SYNTAX); return (ERR_BAD_MAILPROC_CMD_SYNTAX); } char szUserAddress[MAX_ADDR_NAME] = ""; UsrGetAddress(pUI, szUserAddress); /////////////////////////////////////////////////////////////////////////////// // Redirection loop /////////////////////////////////////////////////////////////////////////////// for (int ii = 1; ppszCmdTokens[ii] != NULL; ii++) { /////////////////////////////////////////////////////////////////////////////// // Get message handle /////////////////////////////////////////////////////////////////////////////// QMSG_HANDLE hRedirMessage = QueCreateMessage(hSpoolQueue); if (hRedirMessage == INVALID_QMSG_HANDLE) return (ErrGetErrorCode()); char szQueueFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hSpoolQueue, hRedirMessage, szQueueFilePath); char szAliasAddr[MAX_ADDR_NAME] = ""; if (strchr(ppszCmdTokens[ii], '@') == NULL) SysSNPrintf(szAliasAddr, sizeof(szAliasAddr) - 1, "%s@%s", pUI->pszName, ppszCmdTokens[ii]); else StrSNCpy(szAliasAddr, ppszCmdTokens[ii]); if (USmlCreateSpoolFile(hFSpool, szUserAddress, szAliasAddr, szQueueFilePath, "X-Deliver-To", szUserAddress, NULL) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hRedirMessage); QueCloseMessage(hSpoolQueue, hRedirMessage); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Transfer file to the spool /////////////////////////////////////////////////////////////////////////////// if (QueCommitMessage(hSpoolQueue, hRedirMessage) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hRedirMessage); QueCloseMessage(hSpoolQueue, hRedirMessage); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Log the redir operation /////////////////////////////////////////////////////////////////////////////// if (LMPC.ulFlags & LMPCF_LOG_ENABLED) USmlLogMessage(hFSpool, "LREDIR", ppszCmdTokens[ii]); } return (0); } static int USmlCmd_smtprelay(char **ppszCmdTokens, int iNumTokens, SVRCFG_HANDLE hSvrConfig, UserInfo * pUI, SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, LocalMailProcConfig & LMPC) { /////////////////////////////////////////////////////////////////////////////// // Apply filters ... /////////////////////////////////////////////////////////////////////////////// if (FilFilterMessage(hFSpool, hQueue, hMessage, FILTER_MODE_OUTBOUND) < 0) return (ErrGetErrorCode()); if (iNumTokens < 2) { ErrSetErrorCode(ERR_BAD_MAILPROC_CMD_SYNTAX); return (ERR_BAD_MAILPROC_CMD_SYNTAX); } char **ppszRelays = NULL; if (ppszCmdTokens[1][0] == '#') { if ((ppszRelays = StrTokenize(ppszCmdTokens[1] + 1, ",")) != NULL) { int iRelayCount = StrStringsCount(ppszRelays); srand((unsigned int) time(NULL)); for (int ii = 0; ii < (iRelayCount / 2); ii++) { int iSwap1 = rand() % iRelayCount; int iSwap2 = rand() % iRelayCount; char *pszRly1 = ppszRelays[iSwap1]; char *pszRly2 = ppszRelays[iSwap2]; ppszRelays[iSwap1] = pszRly2; ppszRelays[iSwap2] = pszRly1; } } } else ppszRelays = StrTokenize(ppszCmdTokens[1], ","); if (ppszRelays == NULL) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // This function retrieve the spool file message section and sync the content. // This is necessary before sending the file /////////////////////////////////////////////////////////////////////////////// FileSection FS; if (USmlGetMsgFileSection(hFSpool, FS) < 0) { ErrorPush(); StrFreeStrings(ppszRelays); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Get spool file infos /////////////////////////////////////////////////////////////////////////////// char const *pszSMTPDomain = USmlGetSMTPDomain(hFSpool); char const *pszMailFrom = USmlMailFrom(hFSpool); char const *pszRcptTo = USmlRcptTo(hFSpool); char const *pszSendMailFrom = USmlSendMailFrom(hFSpool); char const *pszSendRcptTo = USmlSendRcptTo(hFSpool); char const *pszSpoolFilePath = USmlGetSpoolFilePath(hFSpool); /////////////////////////////////////////////////////////////////////////////// // Get HELO domain /////////////////////////////////////////////////////////////////////////////// char szHeloDomain[MAX_HOST_NAME] = ""; SvrConfigVar("HeloDomain", szHeloDomain, sizeof(szHeloDomain) - 1, hSvrConfig, ""); char const *pszHeloDomain = IsEmptyString(szHeloDomain) ? NULL : szHeloDomain; SMTPError SMTPE; USmtpInitError(&SMTPE); /////////////////////////////////////////////////////////////////////////////// // By initializing this to zero makes XMail to discharge all mail for domains // that have an empty relay list /////////////////////////////////////////////////////////////////////////////// int iReturnCode = 0; for (int ss = 0; ppszRelays[ss] != NULL; ss++) { SysLogMessage(LOG_LEV_MESSAGE, "USMAIL SMTP-Send RLYS = \"%s\" SMTP = \"%s\" From = \"%s\" To = \"%s\"\n", ppszRelays[ss], pszSMTPDomain, pszMailFrom, pszRcptTo); USmtpCleanupError(&SMTPE); if (USmtpSendMail(ppszRelays[ss], pszHeloDomain, pszSendMailFrom, pszSendRcptTo, &FS, &SMTPE) == 0) { /////////////////////////////////////////////////////////////////////////////// // Log Mailer operation /////////////////////////////////////////////////////////////////////////////// if (LMPC.ulFlags & LMPCF_LOG_ENABLED) USmlLogMessage(hFSpool, "RLYS", ppszRelays[ss]); USmtpCleanupError(&SMTPE); StrFreeStrings(ppszRelays); return (0); } int iErrorCode = ErrGetErrorCode(); char szSmtpError[512] = ""; USmtpGetSMTPError(&SMTPE, szSmtpError, sizeof(szSmtpError)); ErrLogMessage(LOG_LEV_MESSAGE, "USMAIL SMTP-Send RLYS = \"%s\" SMTP = \"%s\" From = \"%s\" To = \"%s\" Failed !\n" "%s = \"%s\"\n", ppszRelays[ss], pszSMTPDomain, pszMailFrom, pszRcptTo, SMTP_ERROR_VARNAME, szSmtpError); QueUtErrLogMessage(hQueue, hMessage, "USMAIL SMTP-Send RLYS = \"%s\" SMTP = \"%s\" From = \"%s\" To = \"%s\" Failed !\n" "%s = \"%s\"\n", ppszRelays[ss], pszSMTPDomain, pszMailFrom, pszRcptTo, SMTP_ERROR_VARNAME, szSmtpError); /////////////////////////////////////////////////////////////////////////////// // If a permanent SMTP error has been detected, then notify the message sender /////////////////////////////////////////////////////////////////////////////// if (USmtpIsFatalError(&SMTPE)) QueUtNotifyPermErrDelivery(hQueue, hMessage, hFSpool, USmtpGetErrorMessage(&SMTPE), USmtpGetErrorServer(&SMTPE), false); iReturnCode = USmtpIsFatalError(&SMTPE) ? iErrorCode : -iErrorCode; } USmtpCleanupError(&SMTPE); StrFreeStrings(ppszRelays); return (iReturnCode); } int USmlGetDomainCustomDir(char *pszCustomDir, int iMaxPath, int iFinalSlash) { CfgGetRootPath(pszCustomDir, iMaxPath); StrNCat(pszCustomDir, SMAIL_DOMAIN_PROC_DIR, iMaxPath); if (iFinalSlash) AppendSlash(pszCustomDir); return (0); } int USmlGetCmdAliasDir(char *pszAliasDir, int iMaxPath, int iFinalSlash) { CfgGetRootPath(pszAliasDir, iMaxPath); StrNCat(pszAliasDir, SMAIL_CMDALIAS_DIR, iMaxPath); if (iFinalSlash) AppendSlash(pszAliasDir); return (0); } int USmlGetCmdAliasFile(char const *pszDomain, char const *pszUser, char *pszAliasFile) { char szAliasDir[SYS_MAX_PATH] = ""; USmlGetCmdAliasDir(szAliasDir, sizeof(szAliasDir), 1); SysSNPrintf(pszAliasFile, SYS_MAX_PATH - 1, "%s%s%s%s.tab", szAliasDir, pszDomain, SYS_SLASH_STR, pszUser); StrLower(pszAliasFile + strlen(szAliasDir)); return (0); } int USmlIsCmdAliasAccount(char const *pszDomain, char const *pszUser, char *pszAliasFile) { char szAliasFile[SYS_MAX_PATH] = ""; if (pszAliasFile == NULL) pszAliasFile = szAliasFile; if (USmlGetCmdAliasFile(pszDomain, pszUser, pszAliasFile) < 0) return (ErrGetErrorCode()); if (!SysExistFile(pszAliasFile)) { ErrSetErrorCode(ERR_NOT_A_CMD_ALIAS); return (ERR_NOT_A_CMD_ALIAS); } return (0); } int USmlCreateCmdAliasDomainDir(char const *pszDomain) { char szAliasDir[SYS_MAX_PATH] = ""; char szDomainAliasDir[SYS_MAX_PATH] = ""; USmlGetCmdAliasDir(szAliasDir, sizeof(szAliasDir), 1); SysSNPrintf(szDomainAliasDir, sizeof(szDomainAliasDir) - 1, "%s%s", szAliasDir, pszDomain); StrLower(szDomainAliasDir + strlen(szAliasDir)); if (SysMakeDir(szDomainAliasDir) < 0) return (ErrGetErrorCode()); return (0); } int USmlDeleteCmdAliasDomainDir(char const *pszDomain) { char szAliasDir[SYS_MAX_PATH] = ""; char szDomainAliasDir[SYS_MAX_PATH] = ""; USmlGetCmdAliasDir(szAliasDir, sizeof(szAliasDir), 1); SysSNPrintf(szDomainAliasDir, sizeof(szDomainAliasDir) - 1, "%s%s", szAliasDir, pszDomain); StrLower(szDomainAliasDir + strlen(szAliasDir)); if (MscClearDirectory(szDomainAliasDir) < 0) return (ErrGetErrorCode()); if (SysRemoveDir(szDomainAliasDir) < 0) return (ErrGetErrorCode()); return (0); } int USmlGetCmdAliasSpoolFile(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char *pszAliasFilePath) { return (QueGetFilePath(hQueue, hMessage, pszAliasFilePath, QUEUE_CUST_DIR)); } int USmlGetCmdAliasCustomFile(SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char const *pszDomain, char const *pszUser, char *pszAliasFilePath) { /////////////////////////////////////////////////////////////////////////////// // Check if exist a spooled copy /////////////////////////////////////////////////////////////////////////////// char const *pszSpoolFilePath = USmlGetSpoolFilePath(hFSpool); USmlGetCmdAliasSpoolFile(hQueue, hMessage, pszAliasFilePath); if (SysExistFile(pszAliasFilePath)) return (0); /////////////////////////////////////////////////////////////////////////////// // Check if this is a cmd alias /////////////////////////////////////////////////////////////////////////////// char szAliasFile[SYS_MAX_PATH] = ""; if (USmlIsCmdAliasAccount(pszDomain, pszUser, szAliasFile) < 0) return (ErrGetErrorCode()); RLCK_HANDLE hResLock = RLckLockSH(szAliasFile); if (hResLock == INVALID_RLCK_HANDLE) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Make a copy into the spool /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(pszAliasFilePath, szAliasFile) < 0) { ErrorPush(); RLckUnlockSH(hResLock); return (ErrorPop()); } RLckUnlockSH(hResLock); return (0); } int USmlDomainCustomFileName(char const *pszDestDomain, char *pszCustFilePath) { /////////////////////////////////////////////////////////////////////////////// // Make domain name lower case /////////////////////////////////////////////////////////////////////////////// char szDestDomain[MAX_HOST_NAME] = ""; StrSNCpy(szDestDomain, pszDestDomain); StrLower(szDestDomain); /////////////////////////////////////////////////////////////////////////////// // Build file name /////////////////////////////////////////////////////////////////////////////// char szCustomDir[SYS_MAX_PATH] = ""; USmlGetDomainCustomDir(szCustomDir, sizeof(szCustomDir), 1); SysSNPrintf(pszCustFilePath, SYS_MAX_PATH - 1, "%s%s.tab", szCustomDir, szDestDomain); return (0); } int USmlGetDomainCustomFile(char const *pszDestDomain, char *pszCustFilePath) { /////////////////////////////////////////////////////////////////////////////// // Make domain name lower case /////////////////////////////////////////////////////////////////////////////// char szDestDomain[MAX_HOST_NAME] = ""; StrSNCpy(szDestDomain, pszDestDomain); StrLower(szDestDomain); /////////////////////////////////////////////////////////////////////////////// // Lookup custom files /////////////////////////////////////////////////////////////////////////////// char szCustomDir[SYS_MAX_PATH] = ""; USmlGetDomainCustomDir(szCustomDir, sizeof(szCustomDir), 1); for (char const *pszSubDom = szDestDomain; pszSubDom != NULL; pszSubDom = strchr(pszSubDom + 1, '.')) { SysSNPrintf(pszCustFilePath, SYS_MAX_PATH - 1, "%s%s.tab", szCustomDir, pszSubDom); if (SysExistFile(pszCustFilePath)) return (0); } SysSNPrintf(pszCustFilePath, SYS_MAX_PATH - 1, "%s.tab", szCustomDir); if (SysExistFile(pszCustFilePath)) return (0); ErrSetErrorCode(ERR_NOT_A_CUSTOM_DOMAIN); return (ERR_NOT_A_CUSTOM_DOMAIN); } int USmlGetDomainCustomSpoolFile(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char *pszCustFilePath) { return (QueGetFilePath(hQueue, hMessage, pszCustFilePath, QUEUE_CUST_DIR)); } int USmlGetUserCustomSpoolFile(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char *pszCustFilePath) { return (QueGetFilePath(hQueue, hMessage, pszCustFilePath, QUEUE_MPRC_DIR)); } int USmlGetDomainMsgCustomFile(SPLF_HANDLE hFSpool, QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char const *pszDestDomain, char *pszCustFilePath) { /////////////////////////////////////////////////////////////////////////////// // Check if exist a spooled copy /////////////////////////////////////////////////////////////////////////////// char const *pszSpoolFilePath = USmlGetSpoolFilePath(hFSpool); USmlGetDomainCustomSpoolFile(hQueue, hMessage, pszCustFilePath); if (SysExistFile(pszCustFilePath)) return (0); /////////////////////////////////////////////////////////////////////////////// // Check if this is a custom domain /////////////////////////////////////////////////////////////////////////////// char szCustDomainFile[SYS_MAX_PATH] = ""; if (USmlGetDomainCustomFile(pszDestDomain, szCustDomainFile) < 0) return (ErrGetErrorCode()); RLCK_HANDLE hResLock = RLckLockSH(szCustDomainFile); if (hResLock == INVALID_RLCK_HANDLE) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Make a copy into the spool /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(pszCustFilePath, szCustDomainFile) < 0) { ErrorPush(); RLckUnlockSH(hResLock); return (ErrorPop()); } RLckUnlockSH(hResLock); return (0); } int USmlGetCustomDomainFile(char const *pszDestDomain, char const *pszCustFilePath) { /////////////////////////////////////////////////////////////////////////////// // Check if this is a custom domain /////////////////////////////////////////////////////////////////////////////// char szCustDomainFile[SYS_MAX_PATH] = ""; if (USmlGetDomainCustomFile(pszDestDomain, szCustDomainFile) < 0) return (ErrGetErrorCode()); char szResLock[SYS_MAX_PATH] = ""; RLCK_HANDLE hResLock = RLckLockSH(CfgGetBasedPath(szCustDomainFile, szResLock, sizeof(szResLock))); if (hResLock == INVALID_RLCK_HANDLE) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Make a copy onto user supplied file /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(pszCustFilePath, szCustDomainFile) < 0) { ErrorPush(); RLckUnlockSH(hResLock); return (ErrorPop()); } RLckUnlockSH(hResLock); return (0); } int USmlSetCustomDomainFile(char const *pszDestDomain, char const *pszCustFilePath) { /////////////////////////////////////////////////////////////////////////////// // Check if this is a custom domain /////////////////////////////////////////////////////////////////////////////// char szCustDomainFile[SYS_MAX_PATH] = ""; USmlDomainCustomFileName(pszDestDomain, szCustDomainFile); char szResLock[SYS_MAX_PATH] = ""; RLCK_HANDLE hResLock = RLckLockEX(CfgGetBasedPath(szCustDomainFile, szResLock, sizeof(szResLock))); if (hResLock == INVALID_RLCK_HANDLE) return (ErrGetErrorCode()); if (pszCustFilePath != NULL) { /////////////////////////////////////////////////////////////////////////////// // Overwrite current file /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(szCustDomainFile, pszCustFilePath) < 0) { ErrorPush(); RLckUnlockEX(hResLock); return (ErrorPop()); } } else SysRemove(szCustDomainFile); RLckUnlockEX(hResLock); return (0); } int USmlCustomizedDomain(char const *pszDestDomain) { char szCustFilePath[SYS_MAX_PATH] = ""; return (USmlGetDomainCustomFile(pszDestDomain, szCustFilePath)); } static int USmlLogMessage(char const *pszSMTPDomain, char const *pszMessageID, char const *pszSmtpMessageID, char const *pszFrom, char const *pszRcpt, char const *pszMedium, char const *pszParam) { char szTime[256] = ""; MscGetTimeNbrString(szTime, sizeof(szTime) - 1); RLCK_HANDLE hResLock = RLckLockEX(SVR_LOGS_DIR SYS_SLASH_STR SMAIL_LOG_FILE); if (hResLock == INVALID_RLCK_HANDLE) return (ErrGetErrorCode()); MscFileLog(SMAIL_LOG_FILE, "\"%s\"" "\t\"%s\"" "\t\"%s\"" "\t\"%s\"" "\t\"%s\"" "\t\"%s\"" "\t\"%s\"" "\t\"%s\"" "\n", pszSMTPDomain, pszMessageID, pszSmtpMessageID, pszFrom, pszRcpt, pszMedium, pszParam, szTime); RLckUnlockEX(hResLock); return (0); } int USmlLogMessage(SPLF_HANDLE hFSpool, char const *pszMedium, char const *pszParam) { char const *pszSMTPDomain = USmlGetSMTPDomain(hFSpool); char const *pszSmtpMessageID = USmlGetSmtpMessageID(hFSpool); char const *pszMessageID = USmlGetSpoolFile(hFSpool); char const *pszMailFrom = USmlMailFrom(hFSpool); char const *pszRcptTo = USmlRcptTo(hFSpool); USmlLogMessage(pszSMTPDomain, pszMessageID, pszSmtpMessageID, pszMailFrom, pszRcptTo, pszMedium, pszParam); return (0); } int USmlParseAddress(char const *pszAddress, char *pszPreAddr, int iMaxPreAddress, char *pszEmailAddr, int iMaxAddress) { for (; (*pszAddress == ' ') || (*pszAddress == '\t'); pszAddress++); if (*pszAddress == '\0') { ErrSetErrorCode(ERR_BAD_TAG_ADDRESS); return (ERR_BAD_TAG_ADDRESS); } char const *pszOpen = strrchr(pszAddress, '<'); if (pszOpen != NULL) { if (pszPreAddr != NULL) { int iPreCount = Min((int) (pszOpen - pszAddress), iMaxPreAddress - 1); strncpy(pszPreAddr, pszAddress, iPreCount); pszPreAddr[iPreCount] = '\0'; StrTrim(pszPreAddr, " \t"); } if (pszEmailAddr != NULL) { char const *pszClose = strrchr(pszAddress, '>'); if (pszClose == NULL) { ErrSetErrorCode(ERR_BAD_TAG_ADDRESS); return (ERR_BAD_TAG_ADDRESS); } int iEmailCount = (int) Min((pszClose - pszOpen) - 1, iMaxAddress - 1); if (iEmailCount < 0) { ErrSetErrorCode(ERR_BAD_TAG_ADDRESS); return (ERR_BAD_TAG_ADDRESS); } strncpy(pszEmailAddr, pszOpen + 1, iEmailCount); pszEmailAddr[iEmailCount] = '\0'; StrTrim(pszEmailAddr, " \t"); } } else { if (pszPreAddr != NULL) SetEmptyString(pszPreAddr); if (pszEmailAddr != NULL) { strncpy(pszEmailAddr, pszAddress, iMaxAddress - 1); pszEmailAddr[iMaxAddress - 1] = '\0'; StrTrim(pszEmailAddr, " \t"); } } return (0); } static int USmlExtractFromAddress(HSLIST & hTagList, char *pszFromAddr, int iMaxAddress) { /////////////////////////////////////////////////////////////////////////////// // Try to discover the "Return-Path" ( or eventually "From" ) tag to setup // the "MAIL FROM: <>" part of the spool message /////////////////////////////////////////////////////////////////////////////// TAG_POSITION TagPosition = TAG_POSITION_INIT; MessageTagData *pMTD = USmlFindTag(hTagList, "Return-Path", TagPosition); if ((pMTD != NULL) && (USmlParseAddress(pMTD->pszTagData, NULL, 0, pszFromAddr, iMaxAddress) == 0)) return (0); TagPosition = TAG_POSITION_INIT; if (((pMTD = USmlFindTag(hTagList, "From", TagPosition)) != NULL) && (USmlParseAddress(pMTD->pszTagData, NULL, 0, pszFromAddr, iMaxAddress) == 0)) return (0); ErrSetErrorCode(ERR_MAILFROM_UNKNOWN); return (ERR_MAILFROM_UNKNOWN); } static char const *USmlAddressFromAtPtr(char const *pszAt, char const *pszBase, char *pszAddress, int iMaxAddress) { char const *pszStart = pszAt; for (; (pszStart >= pszBase) && (strchr("<> \t,\":;'\r\n", *pszStart) == NULL); pszStart--); ++pszStart; char const *pszEnd = pszAt + 1; for (; (*pszEnd != '\0') && (strchr("<> \t,\":;'\r\n", *pszEnd) == NULL); pszEnd++); int iAddrLength = Min((int) (pszEnd - pszStart), iMaxAddress - 1); strncpy(pszAddress, pszStart, iAddrLength); pszAddress[iAddrLength] = '\0'; return (pszEnd); } static char const *USmlAddSingleAddress(char const *pszCurr, char const *pszBase, DynString * pAddrDS, char const *const *ppszMatchDomains, int *piAdded) { *piAdded = 0; char const *pszAt = strchr(pszCurr, '@'); if (pszAt == NULL) return (NULL); char szAddress[MAX_SMTP_ADDRESS] = ""; char szDomain[MAX_ADDR_NAME] = ""; if (((pszCurr = USmlAddressFromAtPtr(pszAt, pszBase, szAddress, sizeof(szAddress) - 1)) != NULL) && (USmtpSplitEmailAddr(szAddress, NULL, szDomain) == 0) && ((ppszMatchDomains == NULL) || StrStringsIMatch(ppszMatchDomains, szDomain)) && (StrIStr(StrDynGet(pAddrDS), szAddress) == NULL)) { if (StrDynSize(pAddrDS) > 0) StrDynAdd(pAddrDS, ADDRESS_TOKENIZER); StrDynAdd(pAddrDS, szAddress); ++(*piAdded); } return (pszCurr); } static int USmlAddAddresses(char const *pszAddrList, DynString * pAddrDS, char const *const *ppszMatchDomains) { int iAddrAdded = 0; int iAdded; char const *pszCurr = pszAddrList; for (; (pszCurr != NULL) && (*pszCurr != '\0');) { pszCurr = USmlAddSingleAddress(pszCurr, pszAddrList, pAddrDS, ppszMatchDomains, &iAdded); if (iAdded) ++iAddrAdded; } return (iAddrAdded); } static char **USmlGetAddressList(HSLIST & hTagList, char const *const *ppszMatchDomains, char const *const *ppszAddrTags) { DynString AddrDS; StrDynInit(&AddrDS); for (int ii = 0; ppszAddrTags[ii] != NULL; ii++) { char const *pszHdrTag = (strchr("+", ppszAddrTags[ii][0]) != NULL) ? ppszAddrTags[ii] + 1 : ppszAddrTags[ii]; TAG_POSITION TagPosition = TAG_POSITION_INIT; MessageTagData *pMTD = USmlFindTag(hTagList, pszHdrTag, TagPosition); for (; pMTD != NULL; pMTD = USmlFindTag(hTagList, pszHdrTag, TagPosition)) { int iAddrAdded = USmlAddAddresses(pMTD->pszTagData, &AddrDS, ppszMatchDomains); /////////////////////////////////////////////////////////////////////////////// // Exclusive tag detected, stop the scan /////////////////////////////////////////////////////////////////////////////// if ((iAddrAdded > 0) && (ppszAddrTags[ii][0] == '+')) goto BuildAddrList; } } /////////////////////////////////////////////////////////////////////////////// // Yes, i know, goto's might be bad. Not in this case though ... /////////////////////////////////////////////////////////////////////////////// BuildAddrList: char **ppszAddresses = StrTokenize(StrDynGet(&AddrDS), ADDRESS_TOKENIZER); StrDynFree(&AddrDS); return (ppszAddresses); } static int USmlExtractToAddress(HSLIST & hTagList, char *pszToAddr, int iMaxAddress) { /////////////////////////////////////////////////////////////////////////////// // Try to extract the "To:" tag from the mail headers /////////////////////////////////////////////////////////////////////////////// TAG_POSITION TagPosition = TAG_POSITION_INIT; MessageTagData *pMTD = USmlFindTag(hTagList, "To", TagPosition); if ((pMTD == NULL) || (USmlParseAddress(pMTD->pszTagData, NULL, 0, pszToAddr, iMaxAddress) < 0)) { ErrSetErrorCode(ERR_RCPTTO_UNKNOWN); return (ERR_RCPTTO_UNKNOWN); } return (0); } static char **USmlBuildTargetRcptList(char const *pszRcptTo, HSLIST & hTagList, const char *pszFetchHdrTags) { char **ppszRcptList = NULL; char **ppszAddrTags = NULL; if ((pszFetchHdrTags != NULL) && ((ppszAddrTags = StrTokenize(pszFetchHdrTags, ",")) == NULL)) return (NULL); if (pszRcptTo == NULL) { if (ppszAddrTags == NULL) { ErrSetErrorCode(ERR_NO_HDR_FETCH_TAGS); return (NULL); } /////////////////////////////////////////////////////////////////////////////// // If the recipient is NULL try to extract addresses from the message using // the supplied tag string /////////////////////////////////////////////////////////////////////////////// if ((ppszRcptList = USmlGetAddressList(hTagList, NULL, ppszAddrTags)) == NULL) { StrFreeStrings(ppszAddrTags); return (NULL); } } else if (*pszRcptTo == '?') { if (ppszAddrTags == NULL) { ErrSetErrorCode(ERR_NO_HDR_FETCH_TAGS); return (NULL); } /////////////////////////////////////////////////////////////////////////////// // Extract matching domains /////////////////////////////////////////////////////////////////////////////// char **ppszDomains = StrTokenize(pszRcptTo, ","); if (ppszDomains == NULL) { StrFreeStrings(ppszAddrTags); return (NULL); } /////////////////////////////////////////////////////////////////////////////// // We need to masquerade incoming domain. In this case "pszRcptTo" is made by // "?" + masquerade-domain /////////////////////////////////////////////////////////////////////////////// if ((ppszRcptList = USmlGetAddressList(hTagList, &ppszDomains[1], ppszAddrTags)) == NULL) { StrFreeStrings(ppszDomains); StrFreeStrings(ppszAddrTags); return (NULL); } int iAddrCount = StrStringsCount(ppszRcptList); for (int ii = 0; ii < iAddrCount; ii++) { char szToUser[MAX_ADDR_NAME] = ""; char szRecipient[MAX_ADDR_NAME] = ""; if (USmtpSplitEmailAddr(ppszRcptList[ii], szToUser, NULL) == 0) { SysSNPrintf(szRecipient, sizeof(szRecipient) - 1, "%s@%s", szToUser, ppszDomains[0] + 1); SysFree(ppszRcptList[ii]); ppszRcptList[ii] = SysStrDup(szRecipient); } } StrFreeStrings(ppszDomains); } else if (*pszRcptTo == '&') { if (ppszAddrTags == NULL) { ErrSetErrorCode(ERR_NO_HDR_FETCH_TAGS); return (NULL); } /////////////////////////////////////////////////////////////////////////////// // Extract matching domains /////////////////////////////////////////////////////////////////////////////// char **ppszDomains = StrTokenize(pszRcptTo, ","); if (ppszDomains == NULL) { StrFreeStrings(ppszAddrTags); return (NULL); } /////////////////////////////////////////////////////////////////////////////// // We need to masquerade incoming domain. In this case "pszRcptTo" is made by // "&" + add-domain /////////////////////////////////////////////////////////////////////////////// if ((ppszRcptList = USmlGetAddressList(hTagList, &ppszDomains[1], ppszAddrTags)) == NULL) { StrFreeStrings(ppszDomains); StrFreeStrings(ppszAddrTags); return (NULL); } int iAddrCount = StrStringsCount(ppszRcptList); for (int ii = 0; ii < iAddrCount; ii++) { char szRecipient[MAX_ADDR_NAME] = ""; SysSNPrintf(szRecipient, sizeof(szRecipient) - 1, "%s%s", ppszRcptList[ii], ppszDomains[0] + 1); SysFree(ppszRcptList[ii]); ppszRcptList[ii] = SysStrDup(szRecipient); } StrFreeStrings(ppszDomains); } else ppszRcptList = StrBuildList(pszRcptTo, NULL); if (ppszAddrTags != NULL) StrFreeStrings(ppszAddrTags); return (ppszRcptList); } int USmlDeliverFetchedMsg(char const *pszSyncAddr, const char *pszFetchHdrTags, char const *pszMailFile) { FILE *pMailFile = fopen(pszMailFile, "rb"); if (pMailFile == NULL) { ErrSetErrorCode(ERR_FILE_OPEN); return (ERR_FILE_OPEN); } /////////////////////////////////////////////////////////////////////////////// // Load message tags /////////////////////////////////////////////////////////////////////////////// HSLIST hTagList; ListInit(hTagList); USmlLoadTags(pMailFile, hTagList); /////////////////////////////////////////////////////////////////////////////// // Extract "MAIL FROM: <>" address /////////////////////////////////////////////////////////////////////////////// char szFromAddr[MAX_SMTP_ADDRESS] = ""; USmlExtractFromAddress(hTagList, szFromAddr, sizeof(szFromAddr) - 1); /////////////////////////////////////////////////////////////////////////////// // Extract recipient list /////////////////////////////////////////////////////////////////////////////// char **ppszRcptList = USmlBuildTargetRcptList(pszSyncAddr, hTagList, pszFetchHdrTags); if (ppszRcptList == NULL) { ErrorPush(); USmlFreeTagsList(hTagList); fclose(pMailFile); return (ErrorPop()); } USmlFreeTagsList(hTagList); /////////////////////////////////////////////////////////////////////////////// // Loop through extracted recipients and deliver /////////////////////////////////////////////////////////////////////////////// int iDeliverCount = 0; int iAddrCount = StrStringsCount(ppszRcptList); for (int ii = 0; ii < iAddrCount; ii++) { /////////////////////////////////////////////////////////////////////////////// // Check address validity and skip invalid ( or not handled ) ones /////////////////////////////////////////////////////////////////////////////// char szDestDomain[MAX_HOST_NAME] = ""; if ((USmtpSplitEmailAddr(ppszRcptList[ii], NULL, szDestDomain) < 0) || ((MDomIsHandledDomain(szDestDomain) < 0) && (USmlCustomizedDomain(szDestDomain) < 0))) continue; /////////////////////////////////////////////////////////////////////////////// // Get message handle /////////////////////////////////////////////////////////////////////////////// QMSG_HANDLE hMessage = QueCreateMessage(hSpoolQueue); if (hMessage == INVALID_QMSG_HANDLE) { ErrorPush(); StrFreeStrings(ppszRcptList); fclose(pMailFile); return (ErrorPop()); } char szQueueFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hSpoolQueue, hMessage, szQueueFilePath); if (USmlCreateSpoolFile(pMailFile, NULL, szFromAddr, ppszRcptList[ii], szQueueFilePath) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hMessage); QueCloseMessage(hSpoolQueue, hMessage); StrFreeStrings(ppszRcptList); fclose(pMailFile); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Transfer file to the spool /////////////////////////////////////////////////////////////////////////////// if (QueCommitMessage(hSpoolQueue, hMessage) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hMessage); QueCloseMessage(hSpoolQueue, hMessage); StrFreeStrings(ppszRcptList); fclose(pMailFile); return (ErrorPop()); } ++iDeliverCount; } StrFreeStrings(ppszRcptList); fclose(pMailFile); /////////////////////////////////////////////////////////////////////////////// // Check if the message has been delivered at least one time /////////////////////////////////////////////////////////////////////////////// if (iDeliverCount == 0) { ErrSetErrorCode(ERR_FETCHMSG_UNDELIVERED); return (ERR_FETCHMSG_UNDELIVERED); } return (0); } static int USmlCreateSpoolFile(FILE * pMailFile, char const *const *ppszInfo, char const *pszMailFrom, char const *pszRcptTo, char const *pszSpoolFile) { FILE *pSpoolFile = fopen(pszSpoolFile, "wb"); if (pSpoolFile == NULL) { ErrSetErrorCode(ERR_FILE_CREATE, pszSpoolFile); return (ERR_FILE_CREATE); } /////////////////////////////////////////////////////////////////////////////// // Write info line /////////////////////////////////////////////////////////////////////////////// if (ppszInfo != NULL) USmtpWriteInfoLine(pSpoolFile, ppszInfo[smsgiClientAddr], ppszInfo[smsgiServerAddr], ppszInfo[smsgiTime]); else { char szTime[256] = ""; MscGetTimeStr(szTime, sizeof(szTime) - 1); USmtpWriteInfoLine(pSpoolFile, LOCAL_ADDRESS ":0", LOCAL_ADDRESS ":0", szTime); } /////////////////////////////////////////////////////////////////////////////// // Write SMTP domain /////////////////////////////////////////////////////////////////////////////// char szSmtpDomain[MAX_HOST_NAME] = ""; if (USmtpSplitEmailAddr(pszRcptTo, NULL, szSmtpDomain) < 0) { ErrorPush(); fclose(pSpoolFile); SysRemove(pszSpoolFile); return (ErrorPop()); } fprintf(pSpoolFile, "%s\r\n", szSmtpDomain); /////////////////////////////////////////////////////////////////////////////// // Write message ID /////////////////////////////////////////////////////////////////////////////// SYS_UINT64 ullMessageID = 0; if (SvrGetMessageID(&ullMessageID) < 0) { ErrorPush(); fclose(pSpoolFile); SysRemove(pszSpoolFile); return (ErrorPop()); } fprintf(pSpoolFile, "P" SYS_LLX_FMT "\r\n", ullMessageID); /////////////////////////////////////////////////////////////////////////////// // Write "MAIL FROM:" /////////////////////////////////////////////////////////////////////////////// fprintf(pSpoolFile, "MAIL FROM: <%s>\r\n", pszMailFrom); /////////////////////////////////////////////////////////////////////////////// // Write "RCPT TO:" /////////////////////////////////////////////////////////////////////////////// fprintf(pSpoolFile, "RCPT TO: <%s>\r\n", pszRcptTo); /////////////////////////////////////////////////////////////////////////////// // Write SPOOL_FILE_DATA_START /////////////////////////////////////////////////////////////////////////////// fprintf(pSpoolFile, "%s\r\n", SPOOL_FILE_DATA_START); /////////////////////////////////////////////////////////////////////////////// // Write message body /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(pSpoolFile, pMailFile, 0, (unsigned long) -1) < 0) { ErrorPush(); fclose(pSpoolFile); SysRemove(pszSpoolFile); return (ErrorPop()); } fclose(pSpoolFile); return (0); } int USmlMailLoopCheck(SPLF_HANDLE hFSpool, SVRCFG_HANDLE hSvrConfig) { SpoolFileData *pSFD = (SpoolFileData *) hFSpool; /////////////////////////////////////////////////////////////////////////////// // Count MTA ops /////////////////////////////////////////////////////////////////////////////// int iLoopsCount = 0; int iMaxMTAOps = SvrGetConfigInt("MaxMTAOps", MAX_MTA_OPS, hSvrConfig); MessageTagData *pMTD = (MessageTagData *) ListFirst(pSFD->hTagList); for (; pMTD != INVALID_SLIST_PTR; pMTD = (MessageTagData *) ListNext(pSFD->hTagList, (PLISTLINK) pMTD)) if ((stricmp(pMTD->pszTagName, "Received") == 0) || (stricmp(pMTD->pszTagName, "X-Deliver-To") == 0)) ++iLoopsCount; /////////////////////////////////////////////////////////////////////////////// // Check MTA count /////////////////////////////////////////////////////////////////////////////// if (iLoopsCount > iMaxMTAOps) { ErrSetErrorCode(ERR_MAIL_LOOP_DETECTED); return (ERR_MAIL_LOOP_DETECTED); } return (0); }