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

Email服务器

开发平台:

Visual C++

  1. /*
  2.  *  SendMail by Davide Libenzi ( sendmail replacement for XMail )
  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. #if defined(WIN32)
  23. #include <windows.h>
  24. #include <stdio.h>
  25. #include <io.h>
  26. #include <direct.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #include <time.h>
  31. #include "AppDefines.h"
  32. #define SYS_SLASH_CHAR              '\'
  33. #define SYS_SLASH_STR               "\"
  34. #define SYS_MAX_PATH                256
  35. #define SysSNPrintf                 _snprintf
  36. #define Sign(v)                     (((v) < 0) ? -1: +1)
  37. #define Min(a, b)                   (((a) < (b)) ? (a): (b))
  38. #define Max(a, b)                   (((a) > (b)) ? (a): (b))
  39. #define Abs(v)                      (((v) > 0) ? (v): -(v))
  40. int SysFileSync(FILE * pFile)
  41. {
  42. if (fflush(pFile) || _commit(_fileno(pFile)))
  43. return (-1);
  44. return (0);
  45. }
  46. int SysPathExist(char const *pszPathName)
  47. {
  48. return ((_access(pszPathName, 0) == 0) ? 1 : 0);
  49. }
  50. int SysMakeDir(char const *pszPathName)
  51. {
  52. return ((_mkdir(pszPathName) == 0) ? 1 : 0);
  53. }
  54. int SysErrNo(void)
  55. {
  56. return (errno);
  57. }
  58. char const *SysErrStr(void)
  59. {
  60. return (strerror(errno));
  61. }
  62. unsigned long SysGetProcessId(void)
  63. {
  64. return ((unsigned long) GetCurrentThreadId());
  65. }
  66. int SysMoveFile(char const *pszOldName, char const *pszNewName)
  67. {
  68. if (!MoveFileEx
  69.     (pszOldName, pszNewName, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED))
  70. return (-1);
  71. return (0);
  72. }
  73. int SysGetHostName(char *pszHostName, int iNameSize)
  74. {
  75. DWORD dwSize = (DWORD) iNameSize;
  76. GetComputerName(pszHostName, &dwSize);
  77. return (0);
  78. }
  79. void SysMsSleep(int iMsTimeout)
  80. {
  81. Sleep(iMsTimeout);
  82. }
  83. char *SysGetEnv(const char *pszVarName)
  84. {
  85. char szRKeyPath[256] = "";
  86. sprintf(szRKeyPath, "SOFTWARE\%s\%s", APP_PRODUCER, APP_NAME_STR);
  87. HKEY hKey;
  88. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRKeyPath, 0, KEY_QUERY_VALUE,
  89.  &hKey) == ERROR_SUCCESS) {
  90. char szKeyValue[2048] = "";
  91. DWORD dwSize = sizeof(szKeyValue), dwKeyType;
  92. if (RegQueryValueEx(hKey, pszVarName, NULL, &dwKeyType, (u_char *) szKeyValue,
  93.     &dwSize) == ERROR_SUCCESS) {
  94. RegCloseKey(hKey);
  95. return (strdup(szKeyValue));
  96. }
  97. RegCloseKey(hKey);
  98. }
  99. const char *pszValue = getenv(pszVarName);
  100. return ((pszValue != NULL) ? strdup(pszValue) : NULL);
  101. }
  102. char *SysGetUserAddress(char *pszUser, int iSize, char const *pszEnvDomain)
  103. {
  104. DWORD dwSize;
  105. char const *pszDomain;
  106. char szUser[256] = "";
  107. char szDomain[256] = "";
  108. dwSize = sizeof(szUser);
  109. GetUserName(szUser, &dwSize);
  110. if ((pszDomain = SysGetEnv(pszEnvDomain)) == NULL) {
  111. dwSize = sizeof(szDomain);
  112. GetComputerName(szDomain, &dwSize);
  113. pszDomain = szDomain;
  114. }
  115. SysSNPrintf(pszUser, iSize, "%s@%s", szUser, pszDomain);
  116. return (pszUser);
  117. }
  118. #else // #if defined(WIN32)
  119. #if defined(__LINUX__) || defined(__SOLARIS__) || defined(__BSD__)
  120. #include <sys/stat.h>
  121. #include <stdio.h>
  122. #include <stdlib.h>
  123. #include <string.h>
  124. #include <ctype.h>
  125. #include <time.h>
  126. #include <fcntl.h>
  127. #include <unistd.h>
  128. #include <errno.h>
  129. #include <dirent.h>
  130. #define SYS_SLASH_CHAR              '/'
  131. #define SYS_SLASH_STR               "/"
  132. #define SYS_MAX_PATH                256
  133. #define SysSNPrintf                 snprintf
  134. #define stricmp                     strcasecmp
  135. #define strnicmp                    strncasecmp
  136. #define Sign(v)                     (((v) < 0) ? -1: +1)
  137. #define Min(a, b)                   (((a) < (b)) ? (a): (b))
  138. #define Max(a, b)                   (((a) > (b)) ? (a): (b))
  139. #define Abs(v)                      (((v) > 0) ? (v): -(v))
  140. int SysFileSync(FILE * pFile)
  141. {
  142. if (fflush(pFile) || fsync(fileno(pFile)))
  143. return (-1);
  144. return (0);
  145. }
  146. int SysPathExist(char const *pszPathName)
  147. {
  148. return ((access(pszPathName, 0) == 0) ? 1 : 0);
  149. }
  150. int SysMakeDir(char const *pszPathName)
  151. {
  152. return ((mkdir(pszPathName, 0700) == 0) ? 1 : 0);
  153. }
  154. int SysErrNo(void)
  155. {
  156. return (errno);
  157. }
  158. char const *SysErrStr(void)
  159. {
  160. return (strerror(errno));
  161. }
  162. unsigned long SysGetProcessId(void)
  163. {
  164. return ((unsigned long) getpid());
  165. }
  166. int SysMoveFile(char const *pszOldName, char const *pszNewName)
  167. {
  168. if (rename(pszOldName, pszNewName) != 0)
  169. return (-1);
  170. return (0);
  171. }
  172. int SysGetHostName(char *pszHostName, int iNameSize)
  173. {
  174. gethostname(pszHostName, iNameSize);
  175. return (0);
  176. }
  177. void SysMsSleep(int iMsTimeout)
  178. {
  179. usleep(iMsTimeout * 1000);
  180. }
  181. char *SysGetEnv(const char *pszVarName)
  182. {
  183. const char *pszValue = getenv(pszVarName);
  184. return ((pszValue != NULL) ? strdup(pszValue) : NULL);
  185. }
  186. char *SysGetUserAddress(char *pszUser, int iSize, char const *pszEnvDomain)
  187. {
  188. char const *pszEnv;
  189. char szUser[256] = "mail";
  190. char szDomain[256] = "localhost";
  191. if ((pszEnv = SysGetEnv("USER")) != NULL) {
  192. strncpy(szUser, pszEnv, sizeof(szUser) - 1);
  193. szUser[sizeof(szUser) - 1] = '';
  194. }
  195. if (((pszEnv = SysGetEnv(pszEnvDomain)) != NULL) ||
  196.     ((pszEnv = SysGetEnv("HOSTNAME")) != NULL)) {
  197. strncpy(szDomain, pszEnv, sizeof(szDomain) - 1);
  198. szDomain[sizeof(szDomain) - 1] = '';
  199. }
  200. SysSNPrintf(pszUser, iSize, "%s@%s", szUser, szDomain);
  201. return (pszUser);
  202. }
  203. #else // #if defined(__LINUX__) || defined(__SOLARIS__)
  204. #error system type not defined !
  205. #endif // #if defined(__LINUX__) || defined(__SOLARIS__)
  206. #endif // #if defined(WIN32)
  207. #define ENV_MAIL_ROOT           "MAIL_ROOT"
  208. #define LOCAL_TEMP_SUBPATH      "spool" SYS_SLASH_STR "temp" SYS_SLASH_STR
  209. #define LOCAL_SUBPATH           "spool" SYS_SLASH_STR "local" SYS_SLASH_STR
  210. #define MAIL_DATA_TAG           "<<MAIL-DATA>>"
  211. #define MAX_ADDR_NAME           256
  212. #define SAPE_OPEN_TENTATIVES    5
  213. #define SAPE_OPEN_DELAY         500
  214. #define ENV_DEFAULT_DOMAIN      "DEFAULT_DOMAIN"
  215. #define SetEmptyString(s)       (s)[0] = ''
  216. #define IsEmptyString(s)        (*(s) == '')
  217. #define StrNCpy(t, s, n)        do { strncpy(t, s, n); (t)[(n) - 1] = ''; } while (0)
  218. #define StrSNCpy(t, s)          StrNCpy(t, s, sizeof(t))
  219. static FILE *SafeOpenFile(char const *pszFilePath, char const *pszMode)
  220. {
  221. FILE *pFile;
  222. for (int ii = 0; ii < SAPE_OPEN_TENTATIVES; ii++) {
  223. if ((pFile = fopen(pszFilePath, pszMode)) != NULL)
  224. return (pFile);
  225. SysMsSleep(SAPE_OPEN_DELAY);
  226. }
  227. return (NULL);
  228. }
  229. static char const *AddressFromAtPtr(char const *pszAt, char const *pszBase, char *pszAddress,
  230.     int iSize)
  231. {
  232. char const *pszStart = pszAt;
  233. for (; (pszStart >= pszBase) && (strchr("<> t,":;'rn", *pszStart) == NULL);
  234.      pszStart--);
  235. ++pszStart;
  236. char const *pszEnd = pszAt + 1;
  237. for (; (*pszEnd != '') && (strchr("<> t,":;'rn", *pszEnd) == NULL); pszEnd++);
  238. int iAddrLength = Min((int) (pszEnd - pszStart), iSize - 1);
  239. strncpy(pszAddress, pszStart, iAddrLength);
  240. pszAddress[iAddrLength] = '';
  241. return (pszEnd);
  242. }
  243. static int EmitRecipients(FILE * pMailFile, char const *pszAddrList)
  244. {
  245. int iRcptCount = 0;
  246. char const *pszCurr = pszAddrList;
  247. for (; (pszCurr != NULL) && (*pszCurr != '');) {
  248. char const *pszAt = strchr(pszCurr, '@');
  249. if (pszAt == NULL)
  250. break;
  251. char szAddress[256] = "";
  252. if ((pszCurr = AddressFromAtPtr(pszAt, pszAddrList, szAddress,
  253. sizeof(szAddress))) != NULL) {
  254. fprintf(pMailFile, "rcpt to:<%s>rn", szAddress);
  255. ++iRcptCount;
  256. }
  257. }
  258. return (iRcptCount);
  259. }
  260. static int GetTime(struct tm &tmLocal, int &iDiffHours, int &iDiffMins, time_t tCurr)
  261. {
  262. if (tCurr == 0)
  263. time(&tCurr);
  264. tmLocal = *localtime(&tCurr);
  265. struct tm tmTimeLOC = tmLocal;
  266. struct tm tmTimeGM;
  267. tmTimeGM = *gmtime(&tCurr);
  268. tmTimeLOC.tm_isdst = 0;
  269. tmTimeGM.tm_isdst = 0;
  270. time_t tLocal = mktime(&tmTimeLOC);
  271. time_t tGM = mktime(&tmTimeGM);
  272. int iSecsDiff = (int) difftime(tLocal, tGM);
  273. int iSignDiff = Sign(iSecsDiff);
  274. int iMinutes = Abs(iSecsDiff) / 60;
  275. iDiffMins = iMinutes % 60;
  276. iDiffHours = iSignDiff * (iMinutes / 60);
  277. return (0);
  278. }
  279. char *MscStrftime(struct tm const *ptmTime, char *pszDateStr, int iSize)
  280. {
  281. const char *pszWDays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  282. const char *pszMonths[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  283. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  284. };
  285. SysSNPrintf(pszDateStr, iSize, "%s, %d %s %d %02d:%02d:%02d",
  286.     pszWDays[ptmTime->tm_wday], ptmTime->tm_mday,
  287.     pszMonths[ptmTime->tm_mon], ptmTime->tm_year + 1900,
  288.     ptmTime->tm_hour, ptmTime->tm_min, ptmTime->tm_sec);
  289. return (pszDateStr);
  290. }
  291. static int GetTimeStr(char *pszTimeStr, int iStringSize, time_t tCurr)
  292. {
  293. int iDiffHours = 0;
  294. int iDiffMins = 0;
  295. struct tm tmTime;
  296. GetTime(tmTime, iDiffHours, iDiffMins, tCurr);
  297. char szDiffTime[128] = "";
  298. if (iDiffHours > 0)
  299. sprintf(szDiffTime, " +%02d%02d", iDiffHours, iDiffMins);
  300. else
  301. sprintf(szDiffTime, " -%02d%02d", -iDiffHours, iDiffMins);
  302. MscStrftime(&tmTime, pszTimeStr, iStringSize - strlen(szDiffTime) - 1);
  303. strcat(pszTimeStr, szDiffTime);
  304. return (0);
  305. }
  306. static char *CopyAddress(char *pszDest, char const *pszAddr, int iSize)
  307. {
  308. char *pszDomain;
  309. if (strchr(pszAddr, '@') || ((pszDomain = SysGetEnv(ENV_DEFAULT_DOMAIN)) == NULL))
  310. StrNCpy(pszDest, pszAddr, iSize);
  311. else
  312. SysSNPrintf(pszDest, iSize, "%s@%s", pszAddr, pszDomain);
  313. return (pszDest);
  314. }
  315. static bool IsRFC822HeaderLine(char const *pszLn)
  316. {
  317. char const *pszColon;
  318. if (!isalpha(*pszLn) || ((pszColon = strchr(pszLn, ':')) == NULL))
  319. return (false);
  320. for (pszLn++; pszLn < pszColon; pszLn++)
  321. if (!(isalpha(*pszLn) || isdigit(*pszLn) ||
  322.       strchr("_-", *pszLn) != NULL))
  323. return (false);
  324. return (true);
  325. }
  326. int main(int iArgCount, char *pszArgs[])
  327. {
  328. ///////////////////////////////////////////////////////////////////////////////
  329. //  Initialize time
  330. ///////////////////////////////////////////////////////////////////////////////
  331. tzset();
  332. ///////////////////////////////////////////////////////////////////////////////
  333. //  Get the mail root path
  334. ///////////////////////////////////////////////////////////////////////////////
  335. int iVarLength = 0;
  336. FILE *pInFile = stdin;
  337. char *pszMailRoot = SysGetEnv(ENV_MAIL_ROOT);
  338. char szMailRoot[SYS_MAX_PATH] = "";
  339. if ((pszMailRoot == NULL) || ((iVarLength = strlen(pszMailRoot)) == 0)) {
  340. if (pszMailRoot != NULL)
  341. free(pszMailRoot);
  342. fprintf(stderr, "cannot find environment variable: %sn", ENV_MAIL_ROOT);
  343. return (1);
  344. }
  345. StrSNCpy(szMailRoot, pszMailRoot);
  346. if (szMailRoot[iVarLength - 1] != SYS_SLASH_CHAR)
  347. strcat(szMailRoot, SYS_SLASH_STR);
  348. free(pszMailRoot);
  349. ///////////////////////////////////////////////////////////////////////////////
  350. //  Parse command line
  351. ///////////////////////////////////////////////////////////////////////////////
  352. int ii;
  353. bool bExtractRcpts = false;
  354. bool bXMailFormat = false;
  355. bool bDotMode = true;
  356. char szMailFrom[256] = "";
  357. char szExtMailFrom[256] = "";
  358. char szInputFile[SYS_MAX_PATH] = "";
  359. char szRcptFile[SYS_MAX_PATH] = "";
  360. SysGetUserAddress(szMailFrom, sizeof(szMailFrom) - 1, ENV_DEFAULT_DOMAIN);
  361. for (ii = 1; ii < iArgCount; ii++) {
  362. if (strcmp(pszArgs[ii], "--") == 0) {
  363. ++ii;
  364. break;
  365. }
  366. if (strcmp(pszArgs[ii], "--rcpt-file") == 0) {
  367. if (++ii < iArgCount)
  368. StrSNCpy(szRcptFile, pszArgs[ii]);
  369. } else if (strcmp(pszArgs[ii], "--xinput-file") == 0) {
  370. if (++ii < iArgCount) {
  371. StrSNCpy(szInputFile, pszArgs[ii]);
  372. bXMailFormat = true;
  373. }
  374. } else if (strcmp(pszArgs[ii], "--input-file") == 0) {
  375. if (++ii < iArgCount)
  376. StrSNCpy(szInputFile, pszArgs[ii]);
  377. } else if ((strcmp(pszArgs[ii], "-i") == 0) ||
  378.    (strcmp(pszArgs[ii], "-oi") == 0)){
  379. bDotMode = false;
  380. } else if (strcmp(pszArgs[ii], "-t") == 0) {
  381. bExtractRcpts = true;
  382. } else if (strncmp(pszArgs[ii], "-f", 2) == 0) {
  383. if (pszArgs[ii][2] != '')
  384. CopyAddress(szMailFrom, pszArgs[ii] + 2,
  385.     sizeof(szMailFrom) - 1);
  386. else if ((ii + 1) < iArgCount) {
  387. CopyAddress(szMailFrom, pszArgs[ii + 1],
  388.     sizeof(szMailFrom) - 1);
  389. ii++;
  390. }
  391. } else if (strncmp(pszArgs[ii], "-F", 2) == 0) {
  392. if (pszArgs[ii][2] != '')
  393. StrSNCpy(szExtMailFrom, pszArgs[ii] + 2);
  394. else if ((ii + 1) < iArgCount) {
  395. StrSNCpy(szExtMailFrom, pszArgs[ii + 1]);
  396. ii++;
  397. }
  398. char const *pszOpen = strchr(szExtMailFrom, '<');
  399. if (pszOpen == NULL)
  400. CopyAddress(szMailFrom, szExtMailFrom,
  401.     sizeof(szMailFrom) - 1);
  402. else {
  403. char szTmpMailFrom[256] = "";
  404. StrSNCpy(szTmpMailFrom, pszOpen + 1);
  405. char *pszClose =
  406. (char *) strchr(szTmpMailFrom, '>');
  407. if (pszClose != NULL)
  408. *pszClose = '';
  409. CopyAddress(szMailFrom, szTmpMailFrom,
  410.     sizeof(szMailFrom) - 1);
  411. }
  412. } else if (strncmp(pszArgs[ii], "-o", 2) == 0) {
  413. } else if ((strcmp(pszArgs[ii], "-L") == 0) ||
  414.    (strcmp(pszArgs[ii], "-O") == 0) ||
  415.    (strcmp(pszArgs[ii], "-R") == 0) ||
  416.    (strcmp(pszArgs[ii], "-X") == 0) ||
  417.    (strcmp(pszArgs[ii], "-V") == 0) ||
  418.    (strcmp(pszArgs[ii], "-N") == 0) ||
  419.    (strncmp(pszArgs[ii], "-qG", 3) == 0) ||
  420.    (strncmp(pszArgs[ii], "-q!", 3) == 0)) {
  421. if ((ii + 1) < iArgCount)
  422. ii++;
  423. } else
  424. break;
  425. }
  426. ///////////////////////////////////////////////////////////////////////////////
  427. //  Check if recipients are supplied
  428. ///////////////////////////////////////////////////////////////////////////////
  429. if (!bExtractRcpts && (ii >= iArgCount) && IsEmptyString(szRcptFile)) {
  430. fprintf(stderr, "empty recipient listn");
  431. return (2);
  432. }
  433. if (!IsEmptyString(szInputFile)) {
  434. if ((pInFile = fopen(szInputFile, "rb")) == NULL) {
  435. perror(szInputFile);
  436. return (3);
  437. }
  438. }
  439. ///////////////////////////////////////////////////////////////////////////////
  440. //  Save recipients index
  441. ///////////////////////////////////////////////////////////////////////////////
  442. int iRcptIndex = ii;
  443. int iRcptCount = iArgCount - iRcptIndex;
  444. ///////////////////////////////////////////////////////////////////////////////
  445. //  Create file name
  446. ///////////////////////////////////////////////////////////////////////////////
  447. char szHostName[256] = "";
  448. char szDataFile[SYS_MAX_PATH] = "";
  449. char szMailFile[SYS_MAX_PATH] = "";
  450. SysGetHostName(szHostName, sizeof(szHostName) - 1);
  451. sprintf(szDataFile, "%s%s%lu000.%lu.%s",
  452. szMailRoot,
  453. LOCAL_TEMP_SUBPATH, (unsigned long) time(NULL), SysGetProcessId(), szHostName);
  454. sprintf(szMailFile, "%s.mail", szDataFile);
  455. ///////////////////////////////////////////////////////////////////////////////
  456. //  Open raw data file
  457. ///////////////////////////////////////////////////////////////////////////////
  458. FILE *pDataFile = fopen(szDataFile, "w+b");
  459. if (pDataFile == NULL) {
  460. perror(szDataFile);
  461. if (pInFile != stdin)
  462. fclose(pInFile);
  463. return (4);
  464. }
  465. ///////////////////////////////////////////////////////////////////////////////
  466. //  Open maildrop file
  467. ///////////////////////////////////////////////////////////////////////////////
  468. FILE *pMailFile = fopen(szMailFile, "wb");
  469. if (pMailFile == NULL) {
  470. perror(szMailFile);
  471. fclose(pDataFile), remove(szDataFile);
  472. if (pInFile != stdin)
  473. fclose(pInFile);
  474. return (5);
  475. }
  476. ///////////////////////////////////////////////////////////////////////////////
  477. //  Emit sender
  478. ///////////////////////////////////////////////////////////////////////////////
  479. fprintf(pMailFile, "mail from:<%s>rn", szMailFrom);
  480. ///////////////////////////////////////////////////////////////////////////////
  481. //  Emit recipients
  482. ///////////////////////////////////////////////////////////////////////////////
  483. for (ii = iRcptIndex; ii < iArgCount; ii++) {
  484. char szAddr[256] = "";
  485. CopyAddress(szAddr, pszArgs[ii], sizeof(szAddr) - 1);
  486. fprintf(pMailFile, "rcpt to:<%s>rn", szAddr);
  487. }
  488. ///////////////////////////////////////////////////////////////////////////////
  489. //  Emit message by reading from stdin
  490. ///////////////////////////////////////////////////////////////////////////////
  491. int iLine;
  492. bool bInHeaders = true;
  493. bool bHasFrom = false;
  494. bool bHasDate = false;
  495. bool bRcptSource = false;
  496. bool bNoEmit = false;
  497. char szBuffer[1536] = "";
  498. for (iLine = 0; fgets(szBuffer, sizeof(szBuffer) - 1, pInFile) != NULL; iLine++) {
  499. int iLineLength = strlen(szBuffer);
  500. for (; (iLineLength > 0) &&
  501.      ((szBuffer[iLineLength - 1] == 'r') || (szBuffer[iLineLength - 1] == 'n'));
  502.      iLineLength--);
  503. szBuffer[iLineLength] = '';
  504. ///////////////////////////////////////////////////////////////////////////////
  505. //  Is it time to stop reading ?
  506. ///////////////////////////////////////////////////////////////////////////////
  507. if (bDotMode && (strcmp(szBuffer, ".") == 0))
  508. break;
  509. ///////////////////////////////////////////////////////////////////////////////
  510. //  Decode XMail spool file format
  511. ///////////////////////////////////////////////////////////////////////////////
  512. if (bXMailFormat) {
  513. if (strcmp(szBuffer, MAIL_DATA_TAG) == 0)
  514. bXMailFormat = false;
  515. continue;
  516. }
  517. ///////////////////////////////////////////////////////////////////////////////
  518. //  Extract mail from
  519. ///////////////////////////////////////////////////////////////////////////////
  520. if (bInHeaders) {
  521. bool bStraightFile = false;
  522. if ((iLine == 0) && !IsRFC822HeaderLine(szBuffer))
  523. bStraightFile = true;
  524. if (bStraightFile || (iLineLength == 0)) {
  525. bInHeaders = false;
  526. bNoEmit = false;
  527. ///////////////////////////////////////////////////////////////////////////////
  528. //  Add mail from ( if not present )
  529. ///////////////////////////////////////////////////////////////////////////////
  530. if (!bHasFrom) {
  531. if (strlen(szExtMailFrom) != 0)
  532. fprintf(pDataFile, "From: %srn", szExtMailFrom);
  533. else
  534. fprintf(pDataFile, "From: <%s>rn", szMailFrom);
  535. }
  536. ///////////////////////////////////////////////////////////////////////////////
  537. //  Add date ( if not present )
  538. ///////////////////////////////////////////////////////////////////////////////
  539. if (!bHasDate) {
  540. char szDate[128] = "";
  541. GetTimeStr(szDate, sizeof(szDate) - 1, time(NULL));
  542. fprintf(pDataFile, "Date: %srn", szDate);
  543. }
  544. if (bStraightFile)
  545. fprintf(pDataFile, "rn");
  546. }
  547. if ((szBuffer[0] == ' ') || (szBuffer[0] == 't')) {
  548. if (bExtractRcpts && bRcptSource) {
  549. int iRcptCurr = EmitRecipients(pMailFile, szBuffer);
  550. if (iRcptCurr > 0)
  551. iRcptCount += iRcptCurr;
  552. }
  553. } else if (iLineLength > 0) {
  554. bNoEmit = (strnicmp(szBuffer, "Bcc:", 4) == 0);
  555. bRcptSource = (strnicmp(szBuffer, "To:", 3) == 0) ||
  556. (strnicmp(szBuffer, "Cc:", 3) == 0) ||
  557. (strnicmp(szBuffer, "Bcc:", 4) == 0);
  558. if (bExtractRcpts && bRcptSource) {
  559. int iRcptCurr = EmitRecipients(pMailFile, szBuffer);
  560. if (iRcptCurr > 0)
  561. iRcptCount += iRcptCurr;
  562. }
  563. if (!bHasFrom && (strnicmp(szBuffer, "From:", 5) == 0))
  564. bHasFrom = true;
  565. if (!bHasDate && (strnicmp(szBuffer, "Date:", 5) == 0))
  566. bHasDate = true;
  567. }
  568. }
  569. ///////////////////////////////////////////////////////////////////////////////
  570. //  Emit mail line
  571. ///////////////////////////////////////////////////////////////////////////////
  572. if (!bNoEmit)
  573. fprintf(pDataFile, "%srn", szBuffer);
  574. }
  575. ///////////////////////////////////////////////////////////////////////////////
  576. //  Close input file if different from stdin
  577. ///////////////////////////////////////////////////////////////////////////////
  578. if (pInFile != stdin)
  579. fclose(pInFile);
  580. ///////////////////////////////////////////////////////////////////////////////
  581. //  Dump recipient file
  582. ///////////////////////////////////////////////////////////////////////////////
  583. if (!IsEmptyString(szRcptFile)) {
  584. FILE *pRcptFile = SafeOpenFile(szRcptFile, "rb");
  585. if (pRcptFile == NULL) {
  586. perror(szRcptFile);
  587. fclose(pDataFile), remove(szDataFile);
  588. fclose(pMailFile), remove(szMailFile);
  589. return (6);
  590. }
  591. while (fgets(szBuffer, sizeof(szBuffer) - 1, pRcptFile) != NULL) {
  592. int iLineLength = strlen(szBuffer);
  593. for (; (iLineLength > 0) &&
  594.      ((szBuffer[iLineLength - 1] == 'r') ||
  595.       (szBuffer[iLineLength - 1] == 'n')); iLineLength--);
  596. szBuffer[iLineLength] = '';
  597. if (iLineLength >= MAX_ADDR_NAME)
  598. continue;
  599. char *pszAt = strchr(szBuffer, '@');
  600. if (pszAt == NULL)
  601. continue;
  602. char szRecipient[MAX_ADDR_NAME] = "";
  603. if (AddressFromAtPtr(pszAt, szBuffer, szRecipient,
  604.      sizeof(szRecipient)) != NULL) {
  605. fprintf(pMailFile, "rcpt to:<%s>rn", szRecipient);
  606. ++iRcptCount;
  607. }
  608. }
  609. fclose(pRcptFile);
  610. }
  611. ///////////////////////////////////////////////////////////////////////////////
  612. //  Check the number of recipients
  613. ///////////////////////////////////////////////////////////////////////////////
  614. if (iRcptCount == 0) {
  615. fprintf(stderr, "empty recipient listn");
  616. fclose(pDataFile), remove(szDataFile);
  617. fclose(pMailFile), remove(szMailFile);
  618. return (7);
  619. }
  620. ///////////////////////////////////////////////////////////////////////////////
  621. //  Empty line separator between maildrop header and data
  622. ///////////////////////////////////////////////////////////////////////////////
  623. fprintf(pMailFile, "rn");
  624. ///////////////////////////////////////////////////////////////////////////////
  625. //  Append data file
  626. ///////////////////////////////////////////////////////////////////////////////
  627. rewind(pDataFile);
  628. unsigned int uReaded;
  629. do {
  630. if (((uReaded = fread(szBuffer, 1, sizeof(szBuffer), pDataFile)) != 0) &&
  631.     (fwrite(szBuffer, 1, uReaded, pMailFile) != uReaded)) {
  632. perror(szMailFile);
  633. fclose(pDataFile), remove(szDataFile);
  634. fclose(pMailFile), remove(szMailFile);
  635. return (8);
  636. }
  637. } while (uReaded == sizeof(szBuffer));
  638. fclose(pDataFile), remove(szDataFile);
  639. ///////////////////////////////////////////////////////////////////////////////
  640. //  Sync and close the mail file
  641. ///////////////////////////////////////////////////////////////////////////////
  642. if ((SysFileSync(pMailFile) < 0) || fclose(pMailFile)) {
  643. remove(szMailFile);
  644. fprintf(stderr, "cannot write file: %sn", szMailFile);
  645. return (9);
  646. }
  647. ///////////////////////////////////////////////////////////////////////////////
  648. //  Move the mail file
  649. ///////////////////////////////////////////////////////////////////////////////
  650. char szDropFile[SYS_MAX_PATH] = "";
  651. sprintf(szDropFile, "%s%s%lu000.%lu.%s",
  652. szMailRoot,
  653. LOCAL_SUBPATH, (unsigned long) time(NULL), SysGetProcessId(), szHostName);
  654. if (SysMoveFile(szMailFile, szDropFile) < 0) {
  655. remove(szMailFile);
  656. fprintf(stderr, "cannot move file: %sn", szMailFile);
  657. return (10);
  658. }
  659. return (0);
  660. }