www.gusucode.com > VC++版的邮件服务器源程序源码程序 > VC++版的邮件服务器源程序源码程序\code\QueueUtils.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 "ShBlocks.h" #include "ResLocks.h" #include "StrUtils.h" #include "SList.h" #include "MD5.h" #include "Base64Enc.h" #include "BuffSock.h" #include "MessQueue.h" #include "MailConfig.h" #include "UsrUtils.h" #include "SvrUtils.h" #include "AppDefines.h" #include "MailSvr.h" #include "MiscUtils.h" #include "SMTPUtils.h" #include "SMAILUtils.h" #include "QueueUtils.h" #define QUE_SMTP_MAILER_ERROR_HDR "X-MailerError" #define QUE_MAILER_HDR "X-MailerServer" static int QueUtDumpFrozen(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, FILE * pListFile); static char *QueUtGetLogEntryVar(char const *pszLog, char const *pszVarName); static char *QueUtGetReplyAddress(SPLF_HANDLE hFSpool); static int QueUtTXErrorNotifySender(SPLF_HANDLE hFSpool, char const *pszAdminAddrVar, char const *pszReason, char const *pszText, char const *pszServer, char const *pszLogFile); static int QueUtTXErrorExNotifySender(SPLF_HANDLE hFSpool, char const *pszMessFilePath, char const *pszAdminAddrVar, char const *pszReason, char const *pszText, char const *pszServer, char const *pszLogFile); static int QueUtTXErrorNotifyRoot(SPLF_HANDLE hFSpool, char const *pszReason, char const *pszLogFile); static int QueUtTXErrorExNotifyRoot(SPLF_HANDLE hFSpool, char const *pszMessFilePath, char const *pszReason, char const *pszLogFile); static int QueUtBuildErrorRespose(char const *pszSMTPDomain, SPLF_HANDLE hFSpool, char const *pszFrom, char const *pszTo, char const *pszResponseFile, char const *pszReason, char const *pszText, char const *pszServer, int iLinesExtra, char const *pszLogFile); static int QueUtDumpFrozen(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, FILE * pListFile) { /////////////////////////////////////////////////////////////////////////////// // Get message file path /////////////////////////////////////////////////////////////////////////////// char szQueueFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hQueue, hMessage, szQueueFilePath); /////////////////////////////////////////////////////////////////////////////// // Load spool file info and make a type check /////////////////////////////////////////////////////////////////////////////// SYS_FILE_INFO FI; if (SysGetFileInfo(szQueueFilePath, FI) < 0) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Load the spool file header /////////////////////////////////////////////////////////////////////////////// SpoolFileHeader SFH; if (USmlLoadSpoolFileHeader(szQueueFilePath, SFH) < 0) return (ErrGetErrorCode()); char *pszFrom = USmlAddrConcat(SFH.ppszFrom); if (pszFrom == NULL) { ErrorPush(); USmlCleanupSpoolFileHeader(SFH); return (ErrorPop()); } char *pszRcpt = USmlAddrConcat(SFH.ppszRcpt); if (pszRcpt == NULL) { ErrorPush(); SysFree(pszFrom); USmlCleanupSpoolFileHeader(SFH); return (ErrorPop()); } char szTime[128] = ""; MscGetTimeNbrString(szTime, sizeof(szTime) - 1, FI.tMod); fprintf(pListFile, "\"%s\"\t" "\"%d\"\t" "\"%d\"\t" "\"<%s>\"\t" "\"<%s>\"\t" "\"%s\"\t" "\"%lu\"\n", QueGetFileName(hMessage), QueGetLevel1(hMessage), QueGetLevel2(hMessage), pszFrom, pszRcpt, szTime, FI.ulSize); SysFree(pszRcpt); SysFree(pszFrom); USmlCleanupSpoolFileHeader(SFH); return (0); } int QueUtGetFrozenList(QUEUE_HANDLE hQueue, char const *pszListFile) { int iNumDirsLevel = QueGetDirsLevel(hQueue); char const *pszRootPath = QueGetRootPath(hQueue); /////////////////////////////////////////////////////////////////////////////// // Creates the list file and start scanning the frozen queue /////////////////////////////////////////////////////////////////////////////// FILE *pListFile = fopen(pszListFile, "wt"); if (pListFile == NULL) { ErrSetErrorCode(ERR_FILE_CREATE, pszListFile); return (ERR_FILE_CREATE); } for (int ii = 0; ii < iNumDirsLevel; ii++) { for (int jj = 0; jj < iNumDirsLevel; jj++) { char szCurrPath[SYS_MAX_PATH] = ""; sprintf(szCurrPath, "%s%d%s%d%s%s", pszRootPath, ii, SYS_SLASH_STR, jj, SYS_SLASH_STR, QUEUE_FROZ_DIR); char szFrozFileName[SYS_MAX_PATH] = ""; FSCAN_HANDLE hFileScan = MscFirstFile(szCurrPath, 0, szFrozFileName); if (hFileScan != INVALID_FSCAN_HANDLE) { do { if (!SYS_IS_VALID_FILENAME(szFrozFileName)) continue; /////////////////////////////////////////////////////////////////////////////// // Create queue file handle /////////////////////////////////////////////////////////////////////////////// QMSG_HANDLE hMessage = QueGetHandle(hQueue, ii, jj, QUEUE_FROZ_DIR, szFrozFileName); if (hMessage != INVALID_QMSG_HANDLE) { QueUtDumpFrozen(hQueue, hMessage, pListFile); QueCloseMessage(hQueue, hMessage); } } while (MscNextFile(hFileScan, szFrozFileName)); MscCloseFindFile(hFileScan); } } } fclose(pListFile); return (0); } int QueUtUnFreezeMessage(QUEUE_HANDLE hQueue, int iLevel1, int iLevel2, char const *pszMessageFile) { /////////////////////////////////////////////////////////////////////////////// // Create queue file handle /////////////////////////////////////////////////////////////////////////////// QMSG_HANDLE hMessage = QueGetHandle(hQueue, iLevel1, iLevel2, QUEUE_FROZ_DIR, pszMessageFile); if (hMessage == INVALID_QMSG_HANDLE) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Init message statistics /////////////////////////////////////////////////////////////////////////////// QueInitMessageStats(hQueue, hMessage); /////////////////////////////////////////////////////////////////////////////// // Try to re-commit the frozen message /////////////////////////////////////////////////////////////////////////////// if (QueCommitMessage(hQueue, hMessage) < 0) { ErrorPush(); QueCloseMessage(hQueue, hMessage); return (ErrorPop()); } return (0); } int QueUtDeleteFrozenMessage(QUEUE_HANDLE hQueue, int iLevel1, int iLevel2, char const *pszMessageFile) { /////////////////////////////////////////////////////////////////////////////// // Create queue file handle /////////////////////////////////////////////////////////////////////////////// QMSG_HANDLE hMessage = QueGetHandle(hQueue, iLevel1, iLevel2, QUEUE_FROZ_DIR, pszMessageFile); if (hMessage == INVALID_QMSG_HANDLE) return (ErrGetErrorCode()); QueCleanupMessage(hQueue, hMessage); QueCloseMessage(hQueue, hMessage); return (0); } int QueUtGetFrozenMsgFile(QUEUE_HANDLE hQueue, int iLevel1, int iLevel2, char const *pszMessageFile, char const *pszOutFile) { /////////////////////////////////////////////////////////////////////////////// // Create queue file handle /////////////////////////////////////////////////////////////////////////////// QMSG_HANDLE hMessage = QueGetHandle(hQueue, iLevel1, iLevel2, QUEUE_FROZ_DIR, pszMessageFile); if (hMessage == INVALID_QMSG_HANDLE) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Get slog file path /////////////////////////////////////////////////////////////////////////////// char szQueueFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hQueue, hMessage, szQueueFilePath); /////////////////////////////////////////////////////////////////////////////// // Copy the requested file /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(pszOutFile, szQueueFilePath) < 0) { ErrorPush(); QueCloseMessage(hQueue, hMessage); return (ErrorPop()); } QueCloseMessage(hQueue, hMessage); return (0); } int QueUtGetFrozenLogFile(QUEUE_HANDLE hQueue, int iLevel1, int iLevel2, char const *pszMessageFile, char const *pszOutFile) { /////////////////////////////////////////////////////////////////////////////// // Create queue file handle /////////////////////////////////////////////////////////////////////////////// QMSG_HANDLE hMessage = QueGetHandle(hQueue, iLevel1, iLevel2, QUEUE_FROZ_DIR, pszMessageFile); if (hMessage == INVALID_QMSG_HANDLE) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Get slog file path /////////////////////////////////////////////////////////////////////////////// char szQueueFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hQueue, hMessage, szQueueFilePath, QUEUE_SLOG_DIR); /////////////////////////////////////////////////////////////////////////////// // Copy the requested file /////////////////////////////////////////////////////////////////////////////// if (MscCopyFile(pszOutFile, szQueueFilePath) < 0) { ErrorPush(); QueCloseMessage(hQueue, hMessage); return (ErrorPop()); } QueCloseMessage(hQueue, hMessage); return (0); } int QueUtErrLogMessage(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char const *pszFormat, ...) { /////////////////////////////////////////////////////////////////////////////// // Get slog file path /////////////////////////////////////////////////////////////////////////////// char szSlogFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hQueue, hMessage, szSlogFilePath, QUEUE_SLOG_DIR); char *pszMessage = NULL; STRSPRINTF(pszMessage, pszFormat, pszFormat); if (pszMessage == NULL) return (ErrGetErrorCode()); if (ErrFileLogString(szSlogFilePath, pszMessage) < 0) { SysFree(pszMessage); return (ErrGetErrorCode()); } SysFree(pszMessage); return (0); } static char *QueUtGetLogEntryVar(char const *pszLog, char const *pszVarName) { char const *pszEPos; char const *pszEnd; if (((pszEPos = strstr(pszLog, pszVarName)) == NULL) || ((pszEPos = strchr(pszEPos, '=')) == NULL)) return (NULL); ++pszEPos; StrSkipSpaces(pszEPos); if (((pszEnd = strchr(pszEPos, '\r')) == NULL) && ((pszEnd = strchr(pszEPos, '\n')) == NULL)) pszEnd = pszEPos + strlen(pszEPos); if (*pszEPos == '"') { ++pszEPos; if (pszEnd[-1] == '"') pszEnd--; } int iVarLength = (int) (pszEnd - pszEPos); if (iVarLength <= 0) return (NULL); char *pszVarValue = (char *) SysAlloc(iVarLength + 1); if (pszVarValue != NULL) { memcpy(pszVarValue, pszEPos, iVarLength); pszVarValue[iVarLength] = '\0'; } return (pszVarValue); } int QueUtGetLastLogInfo(char const *pszLogFilePath, QueLogInfo * pQLI) { char *pszEntry = QueLoadLastLogEntry(pszLogFilePath); pQLI->pszReason = pQLI->pszServer = NULL; if (pszEntry == NULL) return (ErrGetErrorCode()); pQLI->pszReason = QueUtGetLogEntryVar(pszEntry, SMTP_ERROR_VARNAME); pQLI->pszServer = QueUtGetLogEntryVar(pszEntry, SMTP_SERVER_VARNAME); SysFree(pszEntry); return (0); } void QueUtFreeLastLogInfo(QueLogInfo * pQLI) { if (pQLI->pszServer != NULL) SysFree(pQLI->pszServer); if (pQLI->pszReason != NULL) SysFree(pQLI->pszReason); } bool QueUtRemoveSpoolErrors(void) { return (SvrTestConfigFlag("RemoveSpoolErrors", false)); } int QueUtNotifyPermErrDelivery(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, SPLF_HANDLE hFSpool, char const *pszReason, char const *pszServer, bool bCleanup) { /////////////////////////////////////////////////////////////////////////////// // Get message file path /////////////////////////////////////////////////////////////////////////////// char szQueueFilePath[SYS_MAX_PATH] = ""; char szQueueLogFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hQueue, hMessage, szQueueFilePath); QueGetFilePath(hQueue, hMessage, szQueueLogFilePath, QUEUE_SLOG_DIR); /////////////////////////////////////////////////////////////////////////////// // Load log information from the slog file /////////////////////////////////////////////////////////////////////////////// bool bFreeLogInfo = false; QueLogInfo QLI; if ((pszReason == NULL) || (pszServer == NULL)) { QueUtGetLastLogInfo(szQueueLogFilePath, &QLI); if (pszReason == NULL) pszReason = QLI.pszReason; if (pszServer == NULL) pszServer = QLI.pszServer; bFreeLogInfo = true; } int iNotifyResult = QueUtTXErrorExNotifySender(hFSpool, szQueueFilePath, "ErrorsAdmin", pszReason, NULL, pszServer, szQueueLogFilePath); if (bCleanup) QueCleanupMessage(hQueue, hMessage, !QueUtRemoveSpoolErrors()); if (bFreeLogInfo) QueUtFreeLastLogInfo(&QLI); return (0); } int QueUtNotifyTempErrDelivery(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, SPLF_HANDLE hFSpool, char const *pszReason, char const *pszText, char const *pszServer) { /////////////////////////////////////////////////////////////////////////////// // Get message file path /////////////////////////////////////////////////////////////////////////////// char szQueueLogFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hQueue, hMessage, szQueueLogFilePath, QUEUE_SLOG_DIR); /////////////////////////////////////////////////////////////////////////////// // Load log information from the slog file /////////////////////////////////////////////////////////////////////////////// bool bFreeLogInfo = false; QueLogInfo QLI; if ((pszReason == NULL) || (pszServer == NULL)) { QueUtGetLastLogInfo(szQueueLogFilePath, &QLI); if (pszReason == NULL) pszReason = QLI.pszReason; if (pszServer == NULL) pszServer = QLI.pszServer; bFreeLogInfo = true; } int iNotifyResult = QueUtTXErrorNotifySender(hFSpool, "TempErrorsAdmin", pszReason, pszText, pszServer, szQueueLogFilePath); if (bFreeLogInfo) QueUtFreeLastLogInfo(&QLI); return (iNotifyResult); } int QueUtCleanupNotifyRoot(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, SPLF_HANDLE hFSpool, char const *pszReason) { /////////////////////////////////////////////////////////////////////////////// // Get message file path /////////////////////////////////////////////////////////////////////////////// char szQueueFilePath[SYS_MAX_PATH] = ""; char szQueueLogFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hQueue, hMessage, szQueueFilePath); QueGetFilePath(hQueue, hMessage, szQueueLogFilePath, QUEUE_SLOG_DIR); /////////////////////////////////////////////////////////////////////////////// // Load log information from the slog file /////////////////////////////////////////////////////////////////////////////// bool bFreeLogInfo = false; QueLogInfo QLI; if (pszReason == NULL) { QueUtGetLastLogInfo(szQueueLogFilePath, &QLI); pszReason = QLI.pszReason; bFreeLogInfo = true; } int iNotifyResult = QueUtTXErrorExNotifyRoot(hFSpool, szQueueFilePath, pszReason, szQueueLogFilePath); if (bFreeLogInfo) QueUtFreeLastLogInfo(&QLI); QueCleanupMessage(hQueue, hMessage, !QueUtRemoveSpoolErrors()); return (0); } static char *QueUtGetReplyAddress(SPLF_HANDLE hFSpool) { /////////////////////////////////////////////////////////////////////////////// // Extract the sender /////////////////////////////////////////////////////////////////////////////// char const *const *ppszFrom = USmlGetMailFrom(hFSpool); int iFromDomains = StrStringsCount(ppszFrom); if (iFromDomains == 0) { ErrSetErrorCode(ERR_NULL_SENDER); return (NULL); } char const *pszSender = ppszFrom[iFromDomains - 1]; char szSenderDomain[MAX_ADDR_NAME] = ""; char szSenderName[MAX_ADDR_NAME] = ""; if (USmtpSplitEmailAddr(pszSender, szSenderName, szSenderDomain) < 0) return (SysStrDup(pszSender)); /////////////////////////////////////////////////////////////////////////////// // Lookup special reply-to header tags /////////////////////////////////////////////////////////////////////////////// return (SysStrDup(pszSender)); } static int QueUtTXErrorNotifySender(SPLF_HANDLE hFSpool, char const *pszAdminAddrVar, char const *pszReason, char const *pszText, char const *pszServer, char const *pszLogFile) { /////////////////////////////////////////////////////////////////////////////// // Extract the sender /////////////////////////////////////////////////////////////////////////////// char *pszReplyTo = QueUtGetReplyAddress(hFSpool); if (pszReplyTo == NULL) return (ErrGetErrorCode()); /////////////////////////////////////////////////////////////////////////////// // Load configuration handle /////////////////////////////////////////////////////////////////////////////// SVRCFG_HANDLE hSvrConfig = SvrGetConfigHandle(); if (hSvrConfig == INVALID_SVRCFG_HANDLE) { ErrorPush(); SysFree(pszReplyTo); return (ErrorPop()); } char szPMAddress[MAX_ADDR_NAME] = ""; char szMailDomain[MAX_HOST_NAME] = ""; if ((SvrConfigVar("PostMaster", szPMAddress, sizeof(szPMAddress) - 1, hSvrConfig) < 0) || (SvrConfigVar("RootDomain", szMailDomain, sizeof(szMailDomain) - 1, hSvrConfig) < 0)) { SvrReleaseConfigHandle(hSvrConfig); SysFree(pszReplyTo); ErrSetErrorCode(ERR_INCOMPLETE_CONFIG); return (ERR_INCOMPLETE_CONFIG); } /////////////////////////////////////////////////////////////////////////////// // Get message handle /////////////////////////////////////////////////////////////////////////////// int iMsgLinesExtra = SvrGetConfigInt("NotifyMsgLinesExtra", 0, hSvrConfig); bool bSenderLog = SvrTestConfigFlag("NotifySendLogToSender", false, hSvrConfig); QMSG_HANDLE hMessage = QueCreateMessage(hSpoolQueue); if (hMessage == INVALID_QMSG_HANDLE) { ErrorPush(); SvrReleaseConfigHandle(hSvrConfig); SysFree(pszReplyTo); return (ErrorPop()); } char szQueueFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hSpoolQueue, hMessage, szQueueFilePath); /////////////////////////////////////////////////////////////////////////////// // Build error response mail file /////////////////////////////////////////////////////////////////////////////// if (QueUtBuildErrorRespose(szMailDomain, hFSpool, szPMAddress, pszReplyTo, szQueueFilePath, pszReason, pszText, pszServer, iMsgLinesExtra, bSenderLog ? pszLogFile : NULL) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hMessage); QueCloseMessage(hSpoolQueue, hMessage); SvrReleaseConfigHandle(hSvrConfig); SysFree(pszReplyTo); return (ErrorPop()); } SysFree(pszReplyTo); /////////////////////////////////////////////////////////////////////////////// // Send error response mail file /////////////////////////////////////////////////////////////////////////////// if (QueCommitMessage(hSpoolQueue, hMessage) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hMessage); QueCloseMessage(hSpoolQueue, hMessage); SvrReleaseConfigHandle(hSvrConfig); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Notify "error-handler" admin /////////////////////////////////////////////////////////////////////////////// char szEHAdmin[MAX_ADDR_NAME] = ""; if ((SvrConfigVar(pszAdminAddrVar, szEHAdmin, sizeof(szEHAdmin) - 1, hSvrConfig) == 0) && !IsEmptyString(szEHAdmin)) { /////////////////////////////////////////////////////////////////////////////// // Get message handle /////////////////////////////////////////////////////////////////////////////// if ((hMessage = QueCreateMessage(hSpoolQueue)) == INVALID_QMSG_HANDLE) { ErrorPush(); SvrReleaseConfigHandle(hSvrConfig); return (ErrorPop()); } QueGetFilePath(hSpoolQueue, hMessage, szQueueFilePath); /////////////////////////////////////////////////////////////////////////////// // Build error response mail file /////////////////////////////////////////////////////////////////////////////// if (QueUtBuildErrorRespose(szMailDomain, hFSpool, szPMAddress, szEHAdmin, szQueueFilePath, pszReason, pszText, pszServer, iMsgLinesExtra, pszLogFile) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hMessage); QueCloseMessage(hSpoolQueue, hMessage); SvrReleaseConfigHandle(hSvrConfig); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Send error response mail file /////////////////////////////////////////////////////////////////////////////// if (QueCommitMessage(hSpoolQueue, hMessage) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hMessage); QueCloseMessage(hSpoolQueue, hMessage); SvrReleaseConfigHandle(hSvrConfig); return (ErrorPop()); } } SvrReleaseConfigHandle(hSvrConfig); return (0); } static int QueUtTXErrorExNotifySender(SPLF_HANDLE hFSpool, char const *pszMessFilePath, char const *pszAdminAddrVar, char const *pszReason, char const *pszText, char const *pszServer, char const *pszLogFile) { bool bCloseHSpool = false; if (hFSpool == INVALID_SPLF_HANDLE) { if ((hFSpool = USmlCreateHandle(pszMessFilePath)) == INVALID_SPLF_HANDLE) return (ErrGetErrorCode()); bCloseHSpool = true; } int iNotifyResult = QueUtTXErrorNotifySender(hFSpool, pszAdminAddrVar, pszReason, pszText, pszServer, pszLogFile); if (bCloseHSpool) USmlCloseHandle(hFSpool); return (iNotifyResult); } static int QueUtTXErrorNotifyRoot(SPLF_HANDLE hFSpool, char const *pszReason, char const *pszLogFile) { /////////////////////////////////////////////////////////////////////////////// // Load configuration handle /////////////////////////////////////////////////////////////////////////////// SVRCFG_HANDLE hSvrConfig = SvrGetConfigHandle(); if (hSvrConfig == INVALID_SVRCFG_HANDLE) return (ErrGetErrorCode()); char szPMAddress[MAX_ADDR_NAME] = ""; char szMailDomain[MAX_HOST_NAME] = ""; if ((SvrConfigVar("PostMaster", szPMAddress, sizeof(szPMAddress) - 1, hSvrConfig) < 0) || (SvrConfigVar("RootDomain", szMailDomain, sizeof(szMailDomain) - 1, hSvrConfig) < 0)) { SvrReleaseConfigHandle(hSvrConfig); ErrSetErrorCode(ERR_INCOMPLETE_CONFIG); return (ERR_INCOMPLETE_CONFIG); } /////////////////////////////////////////////////////////////////////////////// // Get message handle /////////////////////////////////////////////////////////////////////////////// int iMsgLinesExtra = SvrGetConfigInt("NotifyMsgLinesExtra", 0, hSvrConfig); QMSG_HANDLE hMessage = QueCreateMessage(hSpoolQueue); if (hMessage == INVALID_QMSG_HANDLE) { ErrorPush(); SvrReleaseConfigHandle(hSvrConfig); return (ErrorPop()); } char szQueueFilePath[SYS_MAX_PATH] = ""; QueGetFilePath(hSpoolQueue, hMessage, szQueueFilePath); /////////////////////////////////////////////////////////////////////////////// // Build error response mail file /////////////////////////////////////////////////////////////////////////////// if (QueUtBuildErrorRespose(szMailDomain, hFSpool, szPMAddress, szPMAddress, szQueueFilePath, pszReason, NULL, NULL, iMsgLinesExtra, pszLogFile) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hMessage); QueCloseMessage(hSpoolQueue, hMessage); SvrReleaseConfigHandle(hSvrConfig); return (ErrorPop()); } SvrReleaseConfigHandle(hSvrConfig); /////////////////////////////////////////////////////////////////////////////// // Send error response mail file /////////////////////////////////////////////////////////////////////////////// if (QueCommitMessage(hSpoolQueue, hMessage) < 0) { ErrorPush(); QueCleanupMessage(hSpoolQueue, hMessage); QueCloseMessage(hSpoolQueue, hMessage); return (ErrorPop()); } return (0); } static int QueUtTXErrorExNotifyRoot(SPLF_HANDLE hFSpool, char const *pszMessFilePath, char const *pszReason, char const *pszLogFile) { bool bCloseHSpool = false; if (hFSpool == INVALID_SPLF_HANDLE) { if ((hFSpool = USmlCreateHandle(pszMessFilePath)) == INVALID_SPLF_HANDLE) return (ErrGetErrorCode()); bCloseHSpool = true; } int iNotifyResult = QueUtTXErrorNotifyRoot(hFSpool, pszReason, pszLogFile); if (bCloseHSpool) USmlCloseHandle(hFSpool); return (iNotifyResult); } static int QueUtBuildErrorRespose(char const *pszSMTPDomain, SPLF_HANDLE hFSpool, char const *pszFrom, char const *pszTo, char const *pszResponseFile, char const *pszReason, char const *pszText, char const *pszServer, int iLinesExtra, char const *pszLogFile) { char const *pszSpoolFileName = USmlGetSpoolFile(hFSpool); char const *pszSmtpMsgID = USmlGetSmtpMessageID(hFSpool); /////////////////////////////////////////////////////////////////////////////// // Retrieve a new message ID /////////////////////////////////////////////////////////////////////////////// SYS_UINT64 ullMessageID = 0; if (SvrGetMessageID(&ullMessageID) < 0) return (ErrGetErrorCode()); FILE *pRespFile = fopen(pszResponseFile, "wb"); if (pRespFile == NULL) { ErrSetErrorCode(ERR_FILE_CREATE); return (ERR_FILE_CREATE); } /////////////////////////////////////////////////////////////////////////////// // Try to remap target user address /////////////////////////////////////////////////////////////////////////////// char szDomain[MAX_ADDR_NAME] = ""; char szName[MAX_ADDR_NAME] = ""; char szTo[MAX_ADDR_NAME] = ""; if (USmlMapAddress(pszTo, szDomain, szName) < 0) StrSNCpy(szTo, pszTo); else SysSNPrintf(szTo, sizeof(szTo) - 1, "%s@%s", szName, szDomain); /////////////////////////////////////////////////////////////////////////////// // Get the current time string /////////////////////////////////////////////////////////////////////////////// char szTime[128] = ""; MscGetTimeStr(szTime, sizeof(szTime) - 1); /////////////////////////////////////////////////////////////////////////////// // Write info line /////////////////////////////////////////////////////////////////////////////// USmtpWriteInfoLine(pRespFile, LOCAL_ADDRESS ":0", LOCAL_ADDRESS ":0", szTime); /////////////////////////////////////////////////////////////////////////////// // Write domain /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "%s\r\n", pszSMTPDomain); /////////////////////////////////////////////////////////////////////////////// // Write message ID /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "X" SYS_LLX_FMT "\r\n", ullMessageID); /////////////////////////////////////////////////////////////////////////////// // Write MAIL FROM /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "MAIL FROM:<%s>\r\n", pszFrom); /////////////////////////////////////////////////////////////////////////////// // Write RCPT TO /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "RCPT TO:<%s>\r\n", szTo); /////////////////////////////////////////////////////////////////////////////// // Write SPOOL_FILE_DATA_START /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "%s\r\n", SPOOL_FILE_DATA_START); /////////////////////////////////////////////////////////////////////////////// // Write Date ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "Date: %s\r\n", szTime); /////////////////////////////////////////////////////////////////////////////// // Write X-MessageId ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "X-MessageId: <%s>\r\n", pszSpoolFileName); /////////////////////////////////////////////////////////////////////////////// // Write X-SmtpMessageId ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "X-SmtpMessageId: <%s>\r\n", pszSmtpMsgID); /////////////////////////////////////////////////////////////////////////////// // Write From ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "From: %s PostMaster <%s>\r\n", pszSMTPDomain, pszFrom); /////////////////////////////////////////////////////////////////////////////// // Write To ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "To: %s\r\n", pszTo); /////////////////////////////////////////////////////////////////////////////// // Write Subject ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "Subject: Error sending message [%s] from [%s]\r\n", pszSpoolFileName, pszSMTPDomain); /////////////////////////////////////////////////////////////////////////////// // Write X-MailerServer ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "%s: %s\r\n", QUE_MAILER_HDR, APP_NAME_VERSION_STR); /////////////////////////////////////////////////////////////////////////////// // Write X-SMTP-Mailer-Error ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "%s: Message = [%s] Server = [%s]\r\n", QUE_SMTP_MAILER_ERROR_HDR, pszSpoolFileName, pszSMTPDomain); /////////////////////////////////////////////////////////////////////////////// // Write blank line ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "\r\n"); /////////////////////////////////////////////////////////////////////////////// // Write XMail bounce identifier /////////////////////////////////////////////////////////////////////////////// char const *pszMailFrom = USmlMailFrom(hFSpool); char const *pszRcptTo = USmlRcptTo(hFSpool); fprintf(pRespFile, "[<00>] XMail bounce: Rcpt=[%s];Error=[%s]\r\n\r\n\r\n", pszRcptTo, (pszReason != NULL) ? pszReason : ""); /////////////////////////////////////////////////////////////////////////////// // Write error message ( mail data ) /////////////////////////////////////////////////////////////////////////////// fprintf(pRespFile, "[<01>] Error sending message [%s] from [%s].\r\n\r\n" "ID: <%s>\r\n" "Mail From: <%s>\r\n" "Rcpt To: <%s>\r\n", pszSpoolFileName, pszSMTPDomain, pszSmtpMsgID, pszMailFrom, pszRcptTo); if (pszServer != NULL) { SYS_INET_ADDR SvrAddr; char szIP[128] = "???.???.???.???"; char szServer[MAX_HOST_NAME] = ""; if ((MscGetServerAddress(pszServer, SvrAddr) == 0) && (SysGetHostByAddr(SvrAddr, szServer) == 0)) { pszServer = szServer; SysInetNToA(SvrAddr, szIP); } else StrSNCpy(szIP, pszServer); fprintf(pRespFile, "Server: <%s> [%s]\r\n", pszServer, szIP); } fprintf(pRespFile, "\r\n\r\n"); /////////////////////////////////////////////////////////////////////////////// // Emit the delivery failure reason /////////////////////////////////////////////////////////////////////////////// if (pszReason != NULL) fprintf(pRespFile, "[<02>] The reason of the delivery failure was:\r\n\r\n" "%s\r\n\r\n\r\n", pszReason); /////////////////////////////////////////////////////////////////////////////// // Emit extra text /////////////////////////////////////////////////////////////////////////////// if (pszText != NULL) fprintf(pRespFile, "[<03>] Note:\r\n\r\n" "%s\r\n\r\n\r\n", pszText); /////////////////////////////////////////////////////////////////////////////// // Dump the log file associated with the message /////////////////////////////////////////////////////////////////////////////// char szBuffer[1536] = ""; if (pszLogFile != NULL) { FILE *pLogFile = fopen(pszLogFile, "rb"); if (pLogFile != NULL) { fprintf(pRespFile, "[<04>] Here is listed the message log file:\r\n\r\n"); while (MscGetString(pLogFile, szBuffer, sizeof(szBuffer) - 1) != NULL) fprintf(pRespFile, "%s\r\n", szBuffer); fprintf(pRespFile, "\r\n\r\n"); fclose(pLogFile); } } /////////////////////////////////////////////////////////////////////////////// // This function retrieve the spool file message section and sync the content. // This is necessary before reading the file /////////////////////////////////////////////////////////////////////////////// FileSection FS; if (USmlGetMsgFileSection(hFSpool, FS) < 0) { ErrorPush(); fclose(pRespFile); SysRemove(pszResponseFile); return (ErrorPop()); } /////////////////////////////////////////////////////////////////////////////// // Open spool file /////////////////////////////////////////////////////////////////////////////// FILE *pMsgFile = fopen(FS.szFilePath, "rb"); if (pMsgFile == NULL) { fclose(pRespFile); SysRemove(pszResponseFile); ErrSetErrorCode(ERR_FILE_OPEN, FS.szFilePath); return (ERR_FILE_OPEN); } /////////////////////////////////////////////////////////////////////////////// // Seek at the beginning of the message ( headers section ) /////////////////////////////////////////////////////////////////////////////// fseek(pMsgFile, FS.ulStartOffset, SEEK_SET); fprintf(pRespFile, "[<05>] Here is listed the initial part of the message:\r\n\r\n"); bool bInHeaders = true; while (MscGetString(pMsgFile, szBuffer, sizeof(szBuffer) - 1) != NULL) { char *pszXDomain, *pszTmp; /////////////////////////////////////////////////////////////////////////////// // Mail error loop deteced /////////////////////////////////////////////////////////////////////////////// if ((StrNComp(szBuffer, QUE_SMTP_MAILER_ERROR_HDR) == 0) && ((pszXDomain = strrchr(szBuffer, '[')) != NULL) && ((pszTmp = strrchr(++pszXDomain, ']')) != NULL) && (strnicmp(pszXDomain, pszSMTPDomain, pszTmp - pszXDomain) == 0)){ fclose(pMsgFile); fclose(pRespFile); SysRemove(pszResponseFile); ErrSetErrorCode(ERR_MAIL_ERROR_LOOP); return (ERR_MAIL_ERROR_LOOP); } if (bInHeaders && IsEmptyString(szBuffer)) bInHeaders = false; if (!bInHeaders && (iLinesExtra-- < 0)) break; fprintf(pRespFile, "%s\r\n", szBuffer); } fclose(pMsgFile); fclose(pRespFile); return (0); } int QueUtResendMessage(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, SPLF_HANDLE hFSpool) { /////////////////////////////////////////////////////////////////////////////// // Try to resend the message /////////////////////////////////////////////////////////////////////////////// int iResendResult = QueResendMessage(hQueue, hMessage); /////////////////////////////////////////////////////////////////////////////// // If the message is expired ... /////////////////////////////////////////////////////////////////////////////// if (iResendResult == ERR_SPOOL_FILE_EXPIRED) { /////////////////////////////////////////////////////////////////////////////// // Handle notifications and cleanup the message /////////////////////////////////////////////////////////////////////////////// iResendResult = QueUtNotifyPermErrDelivery(hQueue, hMessage, hFSpool, "The maximum number of delivery attempts has been reached", NULL, true); QueCloseMessage(hQueue, hMessage); } return (iResendResult); }