QueueUtils.cpp
上传用户:woshihumen
上传日期:2013-07-18
资源大小:484k
文件大小:36k
源码类别:

Email服务器

开发平台:

Visual C++

  1. /*
  2.  *  XMail by Davide Libenzi ( Intranet and Internet mail server )
  3.  *  Copyright (C) 1999,..,2004  Davide Libenzi
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  *
  19.  *  Davide Libenzi <davidel@xmailserver.org>
  20.  *
  21.  */
  22. #include "SysInclude.h"
  23. #include "SysDep.h"
  24. #include "SvrDefines.h"
  25. #include "ShBlocks.h"
  26. #include "ResLocks.h"
  27. #include "StrUtils.h"
  28. #include "SList.h"
  29. #include "MD5.h"
  30. #include "Base64Enc.h"
  31. #include "BuffSock.h"
  32. #include "MessQueue.h"
  33. #include "MailConfig.h"
  34. #include "UsrUtils.h"
  35. #include "SvrUtils.h"
  36. #include "AppDefines.h"
  37. #include "MailSvr.h"
  38. #include "MiscUtils.h"
  39. #include "SMTPUtils.h"
  40. #include "SMAILUtils.h"
  41. #include "QueueUtils.h"
  42. #define QUE_SMTP_MAILER_ERROR_HDR   "X-MailerError"
  43. #define QUE_MAILER_HDR              "X-MailerServer"
  44. static int QueUtDumpFrozen(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, FILE * pListFile);
  45. static char *QueUtGetLogEntryVar(char const *pszLog, char const *pszVarName);
  46. static char *QueUtGetReplyAddress(SPLF_HANDLE hFSpool);
  47. static int QueUtTXErrorNotifySender(SPLF_HANDLE hFSpool, char const *pszAdminAddrVar,
  48.     char const *pszReason, char const *pszText,
  49.     char const *pszServer, char const *pszLogFile);
  50. static int QueUtTXErrorExNotifySender(SPLF_HANDLE hFSpool, char const *pszMessFilePath,
  51.       char const *pszAdminAddrVar, char const *pszReason,
  52.       char const *pszText, char const *pszServer,
  53.       char const *pszLogFile);
  54. static int QueUtTXErrorNotifyRoot(SPLF_HANDLE hFSpool, char const *pszReason,
  55.   char const *pszLogFile);
  56. static int QueUtTXErrorExNotifyRoot(SPLF_HANDLE hFSpool, char const *pszMessFilePath,
  57.     char const *pszReason, char const *pszLogFile);
  58. static int QueUtBuildErrorRespose(char const *pszSMTPDomain, SPLF_HANDLE hFSpool,
  59.   char const *pszFrom, char const *pszSmtpFrom, char const *pszTo,
  60.   char const *pszResponseFile, char const *pszReason,
  61.   char const *pszText, char const *pszServer, int iLinesExtra,
  62.   char const *pszLogFile);
  63. static int QueUtDumpFrozen(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, FILE * pListFile)
  64. {
  65. ///////////////////////////////////////////////////////////////////////////////
  66. //  Get message file path
  67. ///////////////////////////////////////////////////////////////////////////////
  68. char szQueueFilePath[SYS_MAX_PATH] = "";
  69. QueGetFilePath(hQueue, hMessage, szQueueFilePath);
  70. ///////////////////////////////////////////////////////////////////////////////
  71. //  Load spool file info and make a type check
  72. ///////////////////////////////////////////////////////////////////////////////
  73. SYS_FILE_INFO FI;
  74. if (SysGetFileInfo(szQueueFilePath, FI) < 0)
  75. return (ErrGetErrorCode());
  76. ///////////////////////////////////////////////////////////////////////////////
  77. //  Load the spool file header
  78. ///////////////////////////////////////////////////////////////////////////////
  79. SpoolFileHeader SFH;
  80. if (USmlLoadSpoolFileHeader(szQueueFilePath, SFH) < 0)
  81. return (ErrGetErrorCode());
  82. char *pszFrom = USmlAddrConcat(SFH.ppszFrom);
  83. if (pszFrom == NULL) {
  84. ErrorPush();
  85. USmlCleanupSpoolFileHeader(SFH);
  86. return (ErrorPop());
  87. }
  88. char *pszRcpt = USmlAddrConcat(SFH.ppszRcpt);
  89. if (pszRcpt == NULL) {
  90. ErrorPush();
  91. SysFree(pszFrom);
  92. USmlCleanupSpoolFileHeader(SFH);
  93. return (ErrorPop());
  94. }
  95. char szTime[128] = "";
  96. MscGetTimeNbrString(szTime, sizeof(szTime) - 1, FI.tMod);
  97. fprintf(pListFile,
  98. ""%s"t"
  99. ""%d"t"
  100. ""%d"t"
  101. ""<%s>"t"
  102. ""<%s>"t"
  103. ""%s"t"
  104. ""%lu"n",
  105. QueGetFileName(hMessage), QueGetLevel1(hMessage), QueGetLevel2(hMessage),
  106. pszFrom, pszRcpt, szTime, FI.ulSize);
  107. SysFree(pszRcpt);
  108. SysFree(pszFrom);
  109. USmlCleanupSpoolFileHeader(SFH);
  110. return (0);
  111. }
  112. int QueUtGetFrozenList(QUEUE_HANDLE hQueue, char const *pszListFile)
  113. {
  114. int iNumDirsLevel = QueGetDirsLevel(hQueue);
  115. char const *pszRootPath = QueGetRootPath(hQueue);
  116. ///////////////////////////////////////////////////////////////////////////////
  117. //  Creates the list file and start scanning the frozen queue
  118. ///////////////////////////////////////////////////////////////////////////////
  119. FILE *pListFile = fopen(pszListFile, "wt");
  120. if (pListFile == NULL) {
  121. ErrSetErrorCode(ERR_FILE_CREATE, pszListFile);
  122. return (ERR_FILE_CREATE);
  123. }
  124. for (int ii = 0; ii < iNumDirsLevel; ii++) {
  125. for (int jj = 0; jj < iNumDirsLevel; jj++) {
  126. char szCurrPath[SYS_MAX_PATH] = "";
  127. sprintf(szCurrPath, "%s%d%s%d%s%s",
  128. pszRootPath, ii, SYS_SLASH_STR, jj, SYS_SLASH_STR,
  129. QUEUE_FROZ_DIR);
  130. char szFrozFileName[SYS_MAX_PATH] = "";
  131. FSCAN_HANDLE hFileScan = MscFirstFile(szCurrPath, 0, szFrozFileName);
  132. if (hFileScan != INVALID_FSCAN_HANDLE) {
  133. do {
  134. if (!SYS_IS_VALID_FILENAME(szFrozFileName))
  135. continue;
  136. ///////////////////////////////////////////////////////////////////////////////
  137. //  Create queue file handle
  138. ///////////////////////////////////////////////////////////////////////////////
  139. QMSG_HANDLE hMessage =
  140.     QueGetHandle(hQueue, ii, jj, QUEUE_FROZ_DIR,
  141.  szFrozFileName);
  142. if (hMessage != INVALID_QMSG_HANDLE) {
  143. QueUtDumpFrozen(hQueue, hMessage, pListFile);
  144. QueCloseMessage(hQueue, hMessage);
  145. }
  146. } while (MscNextFile(hFileScan, szFrozFileName));
  147. MscCloseFindFile(hFileScan);
  148. }
  149. }
  150. }
  151. fclose(pListFile);
  152. return (0);
  153. }
  154. int QueUtUnFreezeMessage(QUEUE_HANDLE hQueue, int iLevel1, int iLevel2,
  155.  char const *pszMessageFile)
  156. {
  157. ///////////////////////////////////////////////////////////////////////////////
  158. //  Create queue file handle
  159. ///////////////////////////////////////////////////////////////////////////////
  160. QMSG_HANDLE hMessage = QueGetHandle(hQueue, iLevel1, iLevel2, QUEUE_FROZ_DIR,
  161.     pszMessageFile);
  162. if (hMessage == INVALID_QMSG_HANDLE)
  163. return (ErrGetErrorCode());
  164. ///////////////////////////////////////////////////////////////////////////////
  165. //  Init message statistics
  166. ///////////////////////////////////////////////////////////////////////////////
  167. QueInitMessageStats(hQueue, hMessage);
  168. ///////////////////////////////////////////////////////////////////////////////
  169. //  Try to re-commit the frozen message
  170. ///////////////////////////////////////////////////////////////////////////////
  171. if (QueCommitMessage(hQueue, hMessage) < 0) {
  172. ErrorPush();
  173. QueCloseMessage(hQueue, hMessage);
  174. return (ErrorPop());
  175. }
  176. return (0);
  177. }
  178. int QueUtDeleteFrozenMessage(QUEUE_HANDLE hQueue, int iLevel1, int iLevel2,
  179.      char const *pszMessageFile)
  180. {
  181. ///////////////////////////////////////////////////////////////////////////////
  182. //  Create queue file handle
  183. ///////////////////////////////////////////////////////////////////////////////
  184. QMSG_HANDLE hMessage = QueGetHandle(hQueue, iLevel1, iLevel2, QUEUE_FROZ_DIR,
  185.     pszMessageFile);
  186. if (hMessage == INVALID_QMSG_HANDLE)
  187. return (ErrGetErrorCode());
  188. QueCleanupMessage(hQueue, hMessage);
  189. QueCloseMessage(hQueue, hMessage);
  190. return (0);
  191. }
  192. int QueUtGetFrozenMsgFile(QUEUE_HANDLE hQueue, int iLevel1, int iLevel2,
  193.   char const *pszMessageFile, char const *pszOutFile)
  194. {
  195. ///////////////////////////////////////////////////////////////////////////////
  196. //  Create queue file handle
  197. ///////////////////////////////////////////////////////////////////////////////
  198. QMSG_HANDLE hMessage = QueGetHandle(hQueue, iLevel1, iLevel2, QUEUE_FROZ_DIR,
  199.     pszMessageFile);
  200. if (hMessage == INVALID_QMSG_HANDLE)
  201. return (ErrGetErrorCode());
  202. ///////////////////////////////////////////////////////////////////////////////
  203. //  Get slog file path
  204. ///////////////////////////////////////////////////////////////////////////////
  205. char szQueueFilePath[SYS_MAX_PATH] = "";
  206. QueGetFilePath(hQueue, hMessage, szQueueFilePath);
  207. ///////////////////////////////////////////////////////////////////////////////
  208. //  Copy the requested file
  209. ///////////////////////////////////////////////////////////////////////////////
  210. if (MscCopyFile(pszOutFile, szQueueFilePath) < 0) {
  211. ErrorPush();
  212. QueCloseMessage(hQueue, hMessage);
  213. return (ErrorPop());
  214. }
  215. QueCloseMessage(hQueue, hMessage);
  216. return (0);
  217. }
  218. int QueUtGetFrozenLogFile(QUEUE_HANDLE hQueue, int iLevel1, int iLevel2,
  219.   char const *pszMessageFile, char const *pszOutFile)
  220. {
  221. ///////////////////////////////////////////////////////////////////////////////
  222. //  Create queue file handle
  223. ///////////////////////////////////////////////////////////////////////////////
  224. QMSG_HANDLE hMessage = QueGetHandle(hQueue, iLevel1, iLevel2, QUEUE_FROZ_DIR,
  225.     pszMessageFile);
  226. if (hMessage == INVALID_QMSG_HANDLE)
  227. return (ErrGetErrorCode());
  228. ///////////////////////////////////////////////////////////////////////////////
  229. //  Get slog file path
  230. ///////////////////////////////////////////////////////////////////////////////
  231. char szQueueFilePath[SYS_MAX_PATH] = "";
  232. QueGetFilePath(hQueue, hMessage, szQueueFilePath, QUEUE_SLOG_DIR);
  233. ///////////////////////////////////////////////////////////////////////////////
  234. //  Copy the requested file
  235. ///////////////////////////////////////////////////////////////////////////////
  236. if (MscCopyFile(pszOutFile, szQueueFilePath) < 0) {
  237. ErrorPush();
  238. QueCloseMessage(hQueue, hMessage);
  239. return (ErrorPop());
  240. }
  241. QueCloseMessage(hQueue, hMessage);
  242. return (0);
  243. }
  244. int QueUtErrLogMessage(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, char const *pszFormat, ...)
  245. {
  246. ///////////////////////////////////////////////////////////////////////////////
  247. //  Get slog file path
  248. ///////////////////////////////////////////////////////////////////////////////
  249. char szSlogFilePath[SYS_MAX_PATH] = "";
  250. QueGetFilePath(hQueue, hMessage, szSlogFilePath, QUEUE_SLOG_DIR);
  251. char *pszMessage = NULL;
  252. STRSPRINTF(pszMessage, pszFormat, pszFormat);
  253. if (pszMessage == NULL)
  254. return (ErrGetErrorCode());
  255. if (ErrFileLogString(szSlogFilePath, pszMessage) < 0) {
  256. SysFree(pszMessage);
  257. return (ErrGetErrorCode());
  258. }
  259. SysFree(pszMessage);
  260. return (0);
  261. }
  262. static char *QueUtGetLogEntryVar(char const *pszLog, char const *pszVarName)
  263. {
  264. char const *pszEPos;
  265. char const *pszEnd;
  266. if (((pszEPos = strstr(pszLog, pszVarName)) == NULL) ||
  267.     ((pszEPos = strchr(pszEPos, '=')) == NULL))
  268. return (NULL);
  269. ++pszEPos;
  270. StrSkipSpaces(pszEPos);
  271. if (((pszEnd = strchr(pszEPos, 'r')) == NULL) &&
  272.     ((pszEnd = strchr(pszEPos, 'n')) == NULL))
  273. pszEnd = pszEPos + strlen(pszEPos);
  274. if (*pszEPos == '"') {
  275. ++pszEPos;
  276. if (pszEnd[-1] == '"')
  277. pszEnd--;
  278. }
  279. int iVarLength = (int) (pszEnd - pszEPos);
  280. if (iVarLength <= 0)
  281. return (NULL);
  282. char *pszVarValue = (char *) SysAlloc(iVarLength + 1);
  283. if (pszVarValue != NULL) {
  284. memcpy(pszVarValue, pszEPos, iVarLength);
  285. pszVarValue[iVarLength] = '';
  286. }
  287. return (pszVarValue);
  288. }
  289. int QueUtGetLastLogInfo(char const *pszLogFilePath, QueLogInfo * pQLI)
  290. {
  291. char *pszEntry = QueLoadLastLogEntry(pszLogFilePath);
  292. pQLI->pszReason = pQLI->pszServer = NULL;
  293. if (pszEntry == NULL)
  294. return (ErrGetErrorCode());
  295. pQLI->pszReason = QueUtGetLogEntryVar(pszEntry, SMTP_ERROR_VARNAME);
  296. pQLI->pszServer = QueUtGetLogEntryVar(pszEntry, SMTP_SERVER_VARNAME);
  297. SysFree(pszEntry);
  298. return (0);
  299. }
  300. void QueUtFreeLastLogInfo(QueLogInfo * pQLI)
  301. {
  302. if (pQLI->pszServer != NULL)
  303. SysFree(pQLI->pszServer);
  304. if (pQLI->pszReason != NULL)
  305. SysFree(pQLI->pszReason);
  306. }
  307. bool QueUtRemoveSpoolErrors(void)
  308. {
  309. return (SvrTestConfigFlag("RemoveSpoolErrors", false));
  310. }
  311. int QueUtNotifyPermErrDelivery(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage,
  312.        SPLF_HANDLE hFSpool, char const *pszReason,
  313.        char const *pszServer, bool bCleanup)
  314. {
  315. ///////////////////////////////////////////////////////////////////////////////
  316. //  Get message file path
  317. ///////////////////////////////////////////////////////////////////////////////
  318. char szQueueFilePath[SYS_MAX_PATH] = "";
  319. char szQueueLogFilePath[SYS_MAX_PATH] = "";
  320. QueGetFilePath(hQueue, hMessage, szQueueFilePath);
  321. QueGetFilePath(hQueue, hMessage, szQueueLogFilePath, QUEUE_SLOG_DIR);
  322. ///////////////////////////////////////////////////////////////////////////////
  323. //  Load log information from the slog file
  324. ///////////////////////////////////////////////////////////////////////////////
  325. bool bFreeLogInfo = false;
  326. QueLogInfo QLI;
  327. if ((pszReason == NULL) || (pszServer == NULL)) {
  328. QueUtGetLastLogInfo(szQueueLogFilePath, &QLI);
  329. if (pszReason == NULL)
  330. pszReason = QLI.pszReason;
  331. if (pszServer == NULL)
  332. pszServer = QLI.pszServer;
  333. bFreeLogInfo = true;
  334. }
  335. int iNotifyResult = QueUtTXErrorExNotifySender(hFSpool, szQueueFilePath,
  336.        "ErrorsAdmin", pszReason, NULL,
  337.        pszServer, szQueueLogFilePath);
  338. if (bCleanup)
  339. QueCleanupMessage(hQueue, hMessage, !QueUtRemoveSpoolErrors());
  340. if (bFreeLogInfo)
  341. QueUtFreeLastLogInfo(&QLI);
  342. return (0);
  343. }
  344. int QueUtNotifyTempErrDelivery(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage,
  345.        SPLF_HANDLE hFSpool, char const *pszReason,
  346.        char const *pszText, char const *pszServer)
  347. {
  348. ///////////////////////////////////////////////////////////////////////////////
  349. //  Get message file path
  350. ///////////////////////////////////////////////////////////////////////////////
  351. char szQueueLogFilePath[SYS_MAX_PATH] = "";
  352. QueGetFilePath(hQueue, hMessage, szQueueLogFilePath, QUEUE_SLOG_DIR);
  353. ///////////////////////////////////////////////////////////////////////////////
  354. //  Load log information from the slog file
  355. ///////////////////////////////////////////////////////////////////////////////
  356. bool bFreeLogInfo = false;
  357. QueLogInfo QLI;
  358. if ((pszReason == NULL) || (pszServer == NULL)) {
  359. QueUtGetLastLogInfo(szQueueLogFilePath, &QLI);
  360. if (pszReason == NULL)
  361. pszReason = QLI.pszReason;
  362. if (pszServer == NULL)
  363. pszServer = QLI.pszServer;
  364. bFreeLogInfo = true;
  365. }
  366. int iNotifyResult = QueUtTXErrorNotifySender(hFSpool, "TempErrorsAdmin",
  367.      pszReason, pszText, pszServer,
  368.      szQueueLogFilePath);
  369. if (bFreeLogInfo)
  370. QueUtFreeLastLogInfo(&QLI);
  371. return (iNotifyResult);
  372. }
  373. int QueUtCleanupNotifyRoot(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage,
  374.    SPLF_HANDLE hFSpool, char const *pszReason)
  375. {
  376. ///////////////////////////////////////////////////////////////////////////////
  377. //  Get message file path
  378. ///////////////////////////////////////////////////////////////////////////////
  379. char szQueueFilePath[SYS_MAX_PATH] = "";
  380. char szQueueLogFilePath[SYS_MAX_PATH] = "";
  381. QueGetFilePath(hQueue, hMessage, szQueueFilePath);
  382. QueGetFilePath(hQueue, hMessage, szQueueLogFilePath, QUEUE_SLOG_DIR);
  383. ///////////////////////////////////////////////////////////////////////////////
  384. //  Load log information from the slog file
  385. ///////////////////////////////////////////////////////////////////////////////
  386. bool bFreeLogInfo = false;
  387. QueLogInfo QLI;
  388. if (pszReason == NULL) {
  389. QueUtGetLastLogInfo(szQueueLogFilePath, &QLI);
  390. pszReason = QLI.pszReason;
  391. bFreeLogInfo = true;
  392. }
  393. int iNotifyResult = QueUtTXErrorExNotifyRoot(hFSpool, szQueueFilePath, pszReason,
  394.      szQueueLogFilePath);
  395. if (bFreeLogInfo)
  396. QueUtFreeLastLogInfo(&QLI);
  397. QueCleanupMessage(hQueue, hMessage, !QueUtRemoveSpoolErrors());
  398. return (0);
  399. }
  400. static char *QueUtGetReplyAddress(SPLF_HANDLE hFSpool)
  401. {
  402. ///////////////////////////////////////////////////////////////////////////////
  403. //  Extract the sender
  404. ///////////////////////////////////////////////////////////////////////////////
  405. char const *const *ppszFrom = USmlGetMailFrom(hFSpool);
  406. int iFromDomains = StrStringsCount(ppszFrom);
  407. if (iFromDomains == 0) {
  408. ErrSetErrorCode(ERR_NULL_SENDER);
  409. return (NULL);
  410. }
  411. char const *pszSender = ppszFrom[iFromDomains - 1];
  412. char szSenderDomain[MAX_ADDR_NAME] = "";
  413. char szSenderName[MAX_ADDR_NAME] = "";
  414. if (USmtpSplitEmailAddr(pszSender, szSenderName, szSenderDomain) < 0)
  415. return (SysStrDup(pszSender));
  416. ///////////////////////////////////////////////////////////////////////////////
  417. //  Lookup special reply-to header tags
  418. ///////////////////////////////////////////////////////////////////////////////
  419. return (SysStrDup(pszSender));
  420. }
  421. static int QueUtTXErrorNotifySender(SPLF_HANDLE hFSpool, char const *pszAdminAddrVar,
  422.     char const *pszReason, char const *pszText,
  423.     char const *pszServer, char const *pszLogFile)
  424. {
  425. ///////////////////////////////////////////////////////////////////////////////
  426. //  Extract the sender
  427. ///////////////////////////////////////////////////////////////////////////////
  428. char *pszReplyTo = QueUtGetReplyAddress(hFSpool);
  429. if (pszReplyTo == NULL)
  430. return (ErrGetErrorCode());
  431. ///////////////////////////////////////////////////////////////////////////////
  432. //  Load configuration handle
  433. ///////////////////////////////////////////////////////////////////////////////
  434. SVRCFG_HANDLE hSvrConfig = SvrGetConfigHandle();
  435. if (hSvrConfig == INVALID_SVRCFG_HANDLE) {
  436. ErrorPush();
  437. SysFree(pszReplyTo);
  438. return (ErrorPop());
  439. }
  440. char szPMAddress[MAX_ADDR_NAME] = "";
  441. char szMailDomain[MAX_HOST_NAME] = "";
  442. if ((SvrConfigVar("PostMaster", szPMAddress, sizeof(szPMAddress) - 1, hSvrConfig) < 0) ||
  443.     (SvrConfigVar("RootDomain", szMailDomain, sizeof(szMailDomain) - 1, hSvrConfig) < 0))
  444. {
  445. SvrReleaseConfigHandle(hSvrConfig);
  446. SysFree(pszReplyTo);
  447. ErrSetErrorCode(ERR_INCOMPLETE_CONFIG);
  448. return (ERR_INCOMPLETE_CONFIG);
  449. }
  450. ///////////////////////////////////////////////////////////////////////////////
  451. //  Get message handle
  452. ///////////////////////////////////////////////////////////////////////////////
  453. int iMsgLinesExtra = SvrGetConfigInt("NotifyMsgLinesExtra", 0, hSvrConfig);
  454. bool bSenderLog = SvrTestConfigFlag("NotifySendLogToSender", false, hSvrConfig);
  455. bool bNoSenderBounce = SvrTestConfigFlag("NoSenderBounce", false, hSvrConfig);
  456. QMSG_HANDLE hMessage = QueCreateMessage(hSpoolQueue);
  457. if (hMessage == INVALID_QMSG_HANDLE) {
  458. ErrorPush();
  459. SvrReleaseConfigHandle(hSvrConfig);
  460. SysFree(pszReplyTo);
  461. return (ErrorPop());
  462. }
  463. char szQueueFilePath[SYS_MAX_PATH] = "";
  464. QueGetFilePath(hSpoolQueue, hMessage, szQueueFilePath);
  465. ///////////////////////////////////////////////////////////////////////////////
  466. //  Build error response mail file
  467. ///////////////////////////////////////////////////////////////////////////////
  468. if (QueUtBuildErrorRespose(szMailDomain, hFSpool, szPMAddress,
  469.    bNoSenderBounce ? "": szPMAddress, pszReplyTo,
  470.    szQueueFilePath, pszReason, pszText, pszServer,
  471.    iMsgLinesExtra, bSenderLog ? pszLogFile : NULL) < 0) {
  472. ErrorPush();
  473. QueCleanupMessage(hSpoolQueue, hMessage);
  474. QueCloseMessage(hSpoolQueue, hMessage);
  475. SvrReleaseConfigHandle(hSvrConfig);
  476. SysFree(pszReplyTo);
  477. return (ErrorPop());
  478. }
  479. SysFree(pszReplyTo);
  480. ///////////////////////////////////////////////////////////////////////////////
  481. //  Send error response mail file
  482. ///////////////////////////////////////////////////////////////////////////////
  483. if (QueCommitMessage(hSpoolQueue, hMessage) < 0) {
  484. ErrorPush();
  485. QueCleanupMessage(hSpoolQueue, hMessage);
  486. QueCloseMessage(hSpoolQueue, hMessage);
  487. SvrReleaseConfigHandle(hSvrConfig);
  488. return (ErrorPop());
  489. }
  490. ///////////////////////////////////////////////////////////////////////////////
  491. //  Notify "error-handler" admin
  492. ///////////////////////////////////////////////////////////////////////////////
  493. char szEHAdmin[MAX_ADDR_NAME] = "";
  494. if ((SvrConfigVar(pszAdminAddrVar, szEHAdmin, sizeof(szEHAdmin) - 1, hSvrConfig) == 0) &&
  495.     !IsEmptyString(szEHAdmin)) {
  496. ///////////////////////////////////////////////////////////////////////////////
  497. //  Get message handle
  498. ///////////////////////////////////////////////////////////////////////////////
  499. if ((hMessage = QueCreateMessage(hSpoolQueue)) == INVALID_QMSG_HANDLE) {
  500. ErrorPush();
  501. SvrReleaseConfigHandle(hSvrConfig);
  502. return (ErrorPop());
  503. }
  504. QueGetFilePath(hSpoolQueue, hMessage, szQueueFilePath);
  505. ///////////////////////////////////////////////////////////////////////////////
  506. //  Build error response mail file
  507. ///////////////////////////////////////////////////////////////////////////////
  508. if (QueUtBuildErrorRespose(szMailDomain, hFSpool, szPMAddress,
  509.    bNoSenderBounce ? "": szPMAddress, szEHAdmin,
  510.    szQueueFilePath, pszReason, pszText,
  511.    pszServer, iMsgLinesExtra, pszLogFile) < 0) {
  512. ErrorPush();
  513. QueCleanupMessage(hSpoolQueue, hMessage);
  514. QueCloseMessage(hSpoolQueue, hMessage);
  515. SvrReleaseConfigHandle(hSvrConfig);
  516. return (ErrorPop());
  517. }
  518. ///////////////////////////////////////////////////////////////////////////////
  519. //  Send error response mail file
  520. ///////////////////////////////////////////////////////////////////////////////
  521. if (QueCommitMessage(hSpoolQueue, hMessage) < 0) {
  522. ErrorPush();
  523. QueCleanupMessage(hSpoolQueue, hMessage);
  524. QueCloseMessage(hSpoolQueue, hMessage);
  525. SvrReleaseConfigHandle(hSvrConfig);
  526. return (ErrorPop());
  527. }
  528. }
  529. SvrReleaseConfigHandle(hSvrConfig);
  530. return (0);
  531. }
  532. static int QueUtTXErrorExNotifySender(SPLF_HANDLE hFSpool, char const *pszMessFilePath,
  533.       char const *pszAdminAddrVar, char const *pszReason,
  534.       char const *pszText, char const *pszServer,
  535.       char const *pszLogFile)
  536. {
  537. bool bCloseHSpool = false;
  538. if (hFSpool == INVALID_SPLF_HANDLE) {
  539. if ((hFSpool = USmlCreateHandle(pszMessFilePath)) == INVALID_SPLF_HANDLE)
  540. return (ErrGetErrorCode());
  541. bCloseHSpool = true;
  542. }
  543. int iNotifyResult = QueUtTXErrorNotifySender(hFSpool, pszAdminAddrVar, pszReason,
  544.      pszText, pszServer, pszLogFile);
  545. if (bCloseHSpool)
  546. USmlCloseHandle(hFSpool);
  547. return (iNotifyResult);
  548. }
  549. static int QueUtTXErrorNotifyRoot(SPLF_HANDLE hFSpool, char const *pszReason,
  550.   char const *pszLogFile)
  551. {
  552. ///////////////////////////////////////////////////////////////////////////////
  553. //  Load configuration handle
  554. ///////////////////////////////////////////////////////////////////////////////
  555. SVRCFG_HANDLE hSvrConfig = SvrGetConfigHandle();
  556. if (hSvrConfig == INVALID_SVRCFG_HANDLE)
  557. return (ErrGetErrorCode());
  558. char szPMAddress[MAX_ADDR_NAME] = "";
  559. char szMailDomain[MAX_HOST_NAME] = "";
  560. if ((SvrConfigVar("PostMaster", szPMAddress, sizeof(szPMAddress) - 1, hSvrConfig) < 0) ||
  561.     (SvrConfigVar("RootDomain", szMailDomain, sizeof(szMailDomain) - 1, hSvrConfig) < 0))
  562. {
  563. SvrReleaseConfigHandle(hSvrConfig);
  564. ErrSetErrorCode(ERR_INCOMPLETE_CONFIG);
  565. return (ERR_INCOMPLETE_CONFIG);
  566. }
  567. ///////////////////////////////////////////////////////////////////////////////
  568. //  Get message handle
  569. ///////////////////////////////////////////////////////////////////////////////
  570. int iMsgLinesExtra = SvrGetConfigInt("NotifyMsgLinesExtra", 0, hSvrConfig);
  571. QMSG_HANDLE hMessage = QueCreateMessage(hSpoolQueue);
  572. if (hMessage == INVALID_QMSG_HANDLE) {
  573. ErrorPush();
  574. SvrReleaseConfigHandle(hSvrConfig);
  575. return (ErrorPop());
  576. }
  577. char szQueueFilePath[SYS_MAX_PATH] = "";
  578. QueGetFilePath(hSpoolQueue, hMessage, szQueueFilePath);
  579. ///////////////////////////////////////////////////////////////////////////////
  580. //  Build error response mail file
  581. ///////////////////////////////////////////////////////////////////////////////
  582. if (QueUtBuildErrorRespose(szMailDomain, hFSpool, szPMAddress, szPMAddress,
  583.    szPMAddress, szQueueFilePath, pszReason, NULL, NULL,
  584.    iMsgLinesExtra, pszLogFile) < 0) {
  585. ErrorPush();
  586. QueCleanupMessage(hSpoolQueue, hMessage);
  587. QueCloseMessage(hSpoolQueue, hMessage);
  588. SvrReleaseConfigHandle(hSvrConfig);
  589. return (ErrorPop());
  590. }
  591. SvrReleaseConfigHandle(hSvrConfig);
  592. ///////////////////////////////////////////////////////////////////////////////
  593. //  Send error response mail file
  594. ///////////////////////////////////////////////////////////////////////////////
  595. if (QueCommitMessage(hSpoolQueue, hMessage) < 0) {
  596. ErrorPush();
  597. QueCleanupMessage(hSpoolQueue, hMessage);
  598. QueCloseMessage(hSpoolQueue, hMessage);
  599. return (ErrorPop());
  600. }
  601. return (0);
  602. }
  603. static int QueUtTXErrorExNotifyRoot(SPLF_HANDLE hFSpool, char const *pszMessFilePath,
  604.     char const *pszReason, char const *pszLogFile)
  605. {
  606. bool bCloseHSpool = false;
  607. if (hFSpool == INVALID_SPLF_HANDLE) {
  608. if ((hFSpool = USmlCreateHandle(pszMessFilePath)) == INVALID_SPLF_HANDLE)
  609. return (ErrGetErrorCode());
  610. bCloseHSpool = true;
  611. }
  612. int iNotifyResult = QueUtTXErrorNotifyRoot(hFSpool, pszReason, pszLogFile);
  613. if (bCloseHSpool)
  614. USmlCloseHandle(hFSpool);
  615. return (iNotifyResult);
  616. }
  617. static int QueUtBuildErrorRespose(char const *pszSMTPDomain, SPLF_HANDLE hFSpool,
  618.   char const *pszFrom, char const *pszSmtpFrom, char const *pszTo,
  619.   char const *pszResponseFile, char const *pszReason,
  620.   char const *pszText, char const *pszServer, int iLinesExtra,
  621.   char const *pszLogFile)
  622. {
  623. char const *pszSpoolFileName = USmlGetSpoolFile(hFSpool);
  624. char const *pszSmtpMsgID = USmlGetSmtpMessageID(hFSpool);
  625. ///////////////////////////////////////////////////////////////////////////////
  626. //  Retrieve a new message ID
  627. ///////////////////////////////////////////////////////////////////////////////
  628. SYS_UINT64 ullMessageID = 0;
  629. if (SvrGetMessageID(&ullMessageID) < 0)
  630. return (ErrGetErrorCode());
  631. FILE *pRespFile = fopen(pszResponseFile, "wb");
  632. if (pRespFile == NULL) {
  633. ErrSetErrorCode(ERR_FILE_CREATE);
  634. return (ERR_FILE_CREATE);
  635. }
  636. ///////////////////////////////////////////////////////////////////////////////
  637. //  Try to remap target user address
  638. ///////////////////////////////////////////////////////////////////////////////
  639. char szDomain[MAX_ADDR_NAME] = "";
  640. char szName[MAX_ADDR_NAME] = "";
  641. char szTo[MAX_ADDR_NAME] = "";
  642. if (USmlMapAddress(pszTo, szDomain, szName) < 0)
  643. StrSNCpy(szTo, pszTo);
  644. else
  645. SysSNPrintf(szTo, sizeof(szTo) - 1, "%s@%s", szName, szDomain);
  646. ///////////////////////////////////////////////////////////////////////////////
  647. //  Get the current time string
  648. ///////////////////////////////////////////////////////////////////////////////
  649. char szTime[128] = "";
  650. MscGetTimeStr(szTime, sizeof(szTime) - 1);
  651. ///////////////////////////////////////////////////////////////////////////////
  652. //  Write info line
  653. ///////////////////////////////////////////////////////////////////////////////
  654. USmtpWriteInfoLine(pRespFile, LOCAL_ADDRESS_SQB ":0",
  655.    LOCAL_ADDRESS_SQB ":0", szTime);
  656. ///////////////////////////////////////////////////////////////////////////////
  657. //  Write domain
  658. ///////////////////////////////////////////////////////////////////////////////
  659. fprintf(pRespFile, "%srn", pszSMTPDomain);
  660. ///////////////////////////////////////////////////////////////////////////////
  661. //  Write message ID
  662. ///////////////////////////////////////////////////////////////////////////////
  663. fprintf(pRespFile, "X" SYS_LLX_FMT "rn", ullMessageID);
  664. ///////////////////////////////////////////////////////////////////////////////
  665. //  Write MAIL FROM
  666. ///////////////////////////////////////////////////////////////////////////////
  667. fprintf(pRespFile, "MAIL FROM:<%s>rn", pszSmtpFrom);
  668. ///////////////////////////////////////////////////////////////////////////////
  669. //  Write RCPT TO
  670. ///////////////////////////////////////////////////////////////////////////////
  671. fprintf(pRespFile, "RCPT TO:<%s>rn", szTo);
  672. ///////////////////////////////////////////////////////////////////////////////
  673. //  Write SPOOL_FILE_DATA_START
  674. ///////////////////////////////////////////////////////////////////////////////
  675. fprintf(pRespFile, "%srn", SPOOL_FILE_DATA_START);
  676. ///////////////////////////////////////////////////////////////////////////////
  677. //  Write Date ( mail data )
  678. ///////////////////////////////////////////////////////////////////////////////
  679. fprintf(pRespFile, "Date:   %srn", szTime);
  680. ///////////////////////////////////////////////////////////////////////////////
  681. //  Write X-MessageId ( mail data )
  682. ///////////////////////////////////////////////////////////////////////////////
  683. fprintf(pRespFile, "X-MessageId: <%s>rn", pszSpoolFileName);
  684. ///////////////////////////////////////////////////////////////////////////////
  685. //  Write X-SmtpMessageId ( mail data )
  686. ///////////////////////////////////////////////////////////////////////////////
  687. fprintf(pRespFile, "X-SmtpMessageId: <%s>rn", pszSmtpMsgID);
  688. ///////////////////////////////////////////////////////////////////////////////
  689. //  Write From ( mail data )
  690. ///////////////////////////////////////////////////////////////////////////////
  691. fprintf(pRespFile, "From: %s PostMaster <%s>rn", pszSMTPDomain, pszFrom);
  692. ///////////////////////////////////////////////////////////////////////////////
  693. //  Write To ( mail data )
  694. ///////////////////////////////////////////////////////////////////////////////
  695. fprintf(pRespFile, "To: %srn", pszTo);
  696. ///////////////////////////////////////////////////////////////////////////////
  697. //  Write Subject ( mail data )
  698. ///////////////////////////////////////////////////////////////////////////////
  699. fprintf(pRespFile, "Subject: Error sending message [%s] from [%s]rn",
  700. pszSpoolFileName, pszSMTPDomain);
  701. ///////////////////////////////////////////////////////////////////////////////
  702. //  Write X-MailerServer ( mail data )
  703. ///////////////////////////////////////////////////////////////////////////////
  704. fprintf(pRespFile, "%s: %srn", QUE_MAILER_HDR, APP_NAME_VERSION_STR);
  705. ///////////////////////////////////////////////////////////////////////////////
  706. //  Write X-SMTP-Mailer-Error ( mail data )
  707. ///////////////////////////////////////////////////////////////////////////////
  708. fprintf(pRespFile, "%s: Message = [%s] Server = [%s]rn",
  709. QUE_SMTP_MAILER_ERROR_HDR, pszSpoolFileName, pszSMTPDomain);
  710. ///////////////////////////////////////////////////////////////////////////////
  711. //  Write blank line ( mail data )
  712. ///////////////////////////////////////////////////////////////////////////////
  713. fprintf(pRespFile, "rn");
  714. ///////////////////////////////////////////////////////////////////////////////
  715. //  Write XMail bounce identifier
  716. ///////////////////////////////////////////////////////////////////////////////
  717. char const *pszMailFrom = USmlMailFrom(hFSpool);
  718. char const *pszRcptTo = USmlRcptTo(hFSpool);
  719. fprintf(pRespFile, "[<00>] XMail bounce: Rcpt=[%s];Error=[%s]rnrnrn",
  720. pszRcptTo, (pszReason != NULL) ? pszReason : "");
  721. ///////////////////////////////////////////////////////////////////////////////
  722. //  Write error message ( mail data )
  723. ///////////////////////////////////////////////////////////////////////////////
  724. fprintf(pRespFile, "[<01>] Error sending message [%s] from [%s].rnrn"
  725. "ID:        <%s>rn"
  726. "Mail From: <%s>rn"
  727. "Rcpt To:   <%s>rn",
  728. pszSpoolFileName, pszSMTPDomain, pszSmtpMsgID, pszMailFrom, pszRcptTo);
  729. if (pszServer != NULL) {
  730. SYS_INET_ADDR SvrAddr;
  731. char szIP[128] = "???.???.???.???";
  732. char szServer[MAX_HOST_NAME] = "";
  733. if ((MscGetServerAddress(pszServer, SvrAddr) == 0) &&
  734.     (SysGetHostByAddr(SvrAddr, szServer) == 0)) {
  735. pszServer = szServer;
  736. SysInetNToA(SvrAddr, szIP);
  737. } else
  738. StrSNCpy(szIP, pszServer);
  739. fprintf(pRespFile, "Server:    <%s> [%s]rn", pszServer, szIP);
  740. }
  741. fprintf(pRespFile, "rnrn");
  742. ///////////////////////////////////////////////////////////////////////////////
  743. //  Emit the delivery failure reason
  744. ///////////////////////////////////////////////////////////////////////////////
  745. if (pszReason != NULL)
  746. fprintf(pRespFile, "[<02>] The reason of the delivery failure was:rnrn"
  747. "%srnrnrn", pszReason);
  748. ///////////////////////////////////////////////////////////////////////////////
  749. //  Emit extra text
  750. ///////////////////////////////////////////////////////////////////////////////
  751. if (pszText != NULL)
  752. fprintf(pRespFile, "[<03>] Note:rnrn" "%srnrnrn", pszText);
  753. ///////////////////////////////////////////////////////////////////////////////
  754. //  Dump the log file associated with the message
  755. ///////////////////////////////////////////////////////////////////////////////
  756. char szBuffer[1536] = "";
  757. if (pszLogFile != NULL) {
  758. FILE *pLogFile = fopen(pszLogFile, "rb");
  759. if (pLogFile != NULL) {
  760. fprintf(pRespFile, "[<04>] Here is listed the message log file:rnrn");
  761. while (MscGetString(pLogFile, szBuffer, sizeof(szBuffer) - 1) != NULL)
  762. fprintf(pRespFile, "%srn", szBuffer);
  763. fprintf(pRespFile, "rnrn");
  764. fclose(pLogFile);
  765. }
  766. }
  767. ///////////////////////////////////////////////////////////////////////////////
  768. //  This function retrieve the spool file message section and sync the content.
  769. //  This is necessary before reading the file
  770. ///////////////////////////////////////////////////////////////////////////////
  771. FileSection FS;
  772. if (USmlGetMsgFileSection(hFSpool, FS) < 0) {
  773. ErrorPush();
  774. fclose(pRespFile);
  775. SysRemove(pszResponseFile);
  776. return (ErrorPop());
  777. }
  778. ///////////////////////////////////////////////////////////////////////////////
  779. //  Open spool file
  780. ///////////////////////////////////////////////////////////////////////////////
  781. FILE *pMsgFile = fopen(FS.szFilePath, "rb");
  782. if (pMsgFile == NULL) {
  783. fclose(pRespFile);
  784. SysRemove(pszResponseFile);
  785. ErrSetErrorCode(ERR_FILE_OPEN, FS.szFilePath);
  786. return (ERR_FILE_OPEN);
  787. }
  788. ///////////////////////////////////////////////////////////////////////////////
  789. //  Seek at the beginning of the message ( headers section )
  790. ///////////////////////////////////////////////////////////////////////////////
  791. fseek(pMsgFile, FS.ulStartOffset, SEEK_SET);
  792. fprintf(pRespFile, "[<05>] Here is listed the initial part of the message:rnrn");
  793. bool bInHeaders = true;
  794. while (MscGetString(pMsgFile, szBuffer, sizeof(szBuffer) - 1) != NULL) {
  795. char *pszXDomain, *pszTmp;
  796. ///////////////////////////////////////////////////////////////////////////////
  797. //  Mail error loop deteced
  798. ///////////////////////////////////////////////////////////////////////////////
  799. if ((StrNComp(szBuffer, QUE_SMTP_MAILER_ERROR_HDR) == 0) &&
  800.     ((pszXDomain = strrchr(szBuffer, '[')) != NULL) &&
  801.     ((pszTmp = strrchr(++pszXDomain, ']')) != NULL) &&
  802.     (strnicmp(pszXDomain, pszSMTPDomain, pszTmp - pszXDomain) == 0)){
  803. fclose(pMsgFile);
  804. fclose(pRespFile);
  805. SysRemove(pszResponseFile);
  806. ErrSetErrorCode(ERR_MAIL_ERROR_LOOP);
  807. return (ERR_MAIL_ERROR_LOOP);
  808. }
  809. if (bInHeaders && IsEmptyString(szBuffer))
  810. bInHeaders = false;
  811. if (!bInHeaders && (iLinesExtra-- < 0))
  812. break;
  813. fprintf(pRespFile, "%srn", szBuffer);
  814. }
  815. fclose(pMsgFile);
  816. fclose(pRespFile);
  817. return (0);
  818. }
  819. int QueUtResendMessage(QUEUE_HANDLE hQueue, QMSG_HANDLE hMessage, SPLF_HANDLE hFSpool)
  820. {
  821. ///////////////////////////////////////////////////////////////////////////////
  822. //  Try to resend the message
  823. ///////////////////////////////////////////////////////////////////////////////
  824. int iResendResult = QueResendMessage(hQueue, hMessage);
  825. ///////////////////////////////////////////////////////////////////////////////
  826. //  If the message is expired ...
  827. ///////////////////////////////////////////////////////////////////////////////
  828. if (iResendResult == ERR_SPOOL_FILE_EXPIRED) {
  829. ///////////////////////////////////////////////////////////////////////////////
  830. //  Handle notifications and cleanup the message
  831. ///////////////////////////////////////////////////////////////////////////////
  832. iResendResult = QueUtNotifyPermErrDelivery(hQueue, hMessage, hFSpool,
  833.    "The maximum number of delivery attempts has been reached",
  834.    NULL, true);
  835. QueCloseMessage(hQueue, hMessage);
  836. }
  837. return (iResendResult);
  838. }