The XMail's  sendmail  in version 1.2 is buggy.
Attached with this message you'll find the fixed version.




- Davide



-- Attached file included as plaintext by Listar --
-- File: SendMail.cpp

/*
 *  SendMail by Davide Libenzi ( sendmail replacement for XMail )
 *  Copyright (C) 1999,2000,2001  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 <[EMAIL PROTECTED]>
 *
 */

#if defined(WIN32)

#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <direct.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "AppDefines.h"




#define SYS_SLASH_CHAR              '\\'
#define SYS_SLASH_STR               "\\"
#define SYS_MAX_PATH                256




int             SysFileSync(FILE *pFile)
{

    if (fflush(pFile) || _commit(_fileno(pFile)))
        return (-1);

    return (0);

}

int             SysPathExist(char const * pszPathName)
{

    return ((_access(pszPathName, 0) == 0) ? 1 : 0);

}

int             SysMakeDir(char const * pszPathName)
{

    return ((_mkdir(pszPathName) == 0) ? 1 : 0);

}

int             SysErrNo(void)
{

    return (errno);

}

char const     *SysErrStr(void)
{

    return (strerror(errno));

}

unsigned long   SysGetProcessId(void)
{

    return ((unsigned long) GetCurrentThreadId());

}

int             SysMoveFile(char const * pszOldName, char const * pszNewName)
{

    if (!MoveFileEx(pszOldName, pszNewName, MOVEFILE_REPLACE_EXISTING | 
MOVEFILE_COPY_ALLOWED))
        return (-1);

    return (0);

}

int             SysGetHostName(char * pszHostName, int iNameSize)
{

    DWORD           dwSize = (DWORD) iNameSize;

    GetComputerName(pszHostName, &dwSize);

    return (0);

}

void            SysMsSleep(int iMsTimeout)
{

    Sleep(iMsTimeout);

}

char           *SysGetEnv(const char *pszVarName)
{

    char            szRKeyPath[256] = "";

    sprintf(szRKeyPath, "SOFTWARE\\%s\\%s", APP_PRODUCER, APP_NAME_STR);

    HKEY            hKey;

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szRKeyPath, 0, KEY_QUERY_VALUE,
                    &hKey) == ERROR_SUCCESS)
    {
        char            szKeyValue[2048] = "";
        DWORD           dwSize = sizeof(szKeyValue),
                        dwKeyType;

        if (RegQueryValueEx(hKey, pszVarName, NULL, &dwKeyType, (u_char *) szKeyValue,
                        &dwSize) == ERROR_SUCCESS)
        {
            RegCloseKey(hKey);

            return (strdup(szKeyValue));
        }

        RegCloseKey(hKey);
    }

    const char     *pszValue = getenv(pszVarName);

    return ((pszValue != NULL) ? strdup(pszValue) : NULL);

}

#else           // #if defined(WIN32)
#if defined(__LINUX__) || defined(__SOLARIS__) || defined(__FREEBSD__)

#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>



#define SYS_SLASH_CHAR              '/'
#define SYS_SLASH_STR               "/"
#define SYS_MAX_PATH                256

#define stricmp                     strcasecmp
#define strnicmp                    strncasecmp




int             SysFileSync(FILE *pFile)
{

    if (fflush(pFile) || fsync(fileno(pFile)))
        return (-1);

    return (0);

}

int             SysPathExist(char const * pszPathName)
{

    return ((access(pszPathName, 0) == 0) ? 1 : 0);

}

int             SysMakeDir(char const * pszPathName)
{

    return ((mkdir(pszPathName, 0700) == 0) ? 1 : 0);

}

int             SysErrNo(void)
{

    return (errno);

}

char const     *SysErrStr(void)
{

    return (strerror(errno));

}

unsigned long   SysGetProcessId(void)
{

    return ((unsigned long) getpid());

}

int             SysMoveFile(char const * pszOldName, char const * pszNewName)
{

    if (rename(pszOldName, pszNewName) != 0)
        return (-1);

    return (0);

}

int             SysGetHostName(char * pszHostName, int iNameSize)
{

    gethostname(pszHostName, iNameSize);

    return (0);

}

void            SysMsSleep(int iMsTimeout)
{

    usleep(iMsTimeout * 1000);

}

char           *SysGetEnv(const char *pszVarName)
{

    const char     *pszValue = getenv(pszVarName);

    return ((pszValue != NULL) ? strdup(pszValue) : NULL);

}


#else           // #if defined(__LINUX__) || defined(__SOLARIS__)

#error system type not defined !

#endif          // #if defined(__LINUX__) || defined(__SOLARIS__)
#endif          // #if defined(WIN32)




#define ENV_MAIL_ROOT           "MAIL_ROOT"
#define LOCAL_TEMP_SUBPATH      "spool" SYS_SLASH_STR "temp" SYS_SLASH_STR
#define LOCAL_SUBPATH           "spool" SYS_SLASH_STR "local" SYS_SLASH_STR
#define MAIL_DATA_TAG           "<<MAIL-DATA>>"
#define MAX_ADDR_NAME           256
#define SAPE_OPEN_TENTATIVES    5
#define SAPE_OPEN_DELAY         500

#define SetEmptyString(s)       (s)[0] = '\0'
#define IsEmptyString(s)        (*(s) == '\0')
#define StrNCpy(t, s, n)        do { strncpy(t, s, n); (t)[(n) - 1] = '\0'; } while (0)
#define StrSNCpy(t, s)          StrNCpy(t, s, sizeof(t))



static FILE    *SafeOpenFile(char const * pszFilePath, char const * pszMode)
{

    FILE           *pFile;

    for (int ii = 0; ii < SAPE_OPEN_TENTATIVES; ii++)
    {
        if ((pFile = fopen(pszFilePath, pszMode)) != NULL)
            return (pFile);

        SysMsSleep(SAPE_OPEN_DELAY);
    }

    return (NULL);

}



static char const *AddressFromAtPtr(char const * pszAt, char const * pszBase,
                        char *pszAddress)
{

    char const     *pszStart = pszAt;

    for (; (pszStart >= pszBase) && (strchr("<> \t,\":;'\r\n", *pszStart) == NULL); 
pszStart--);

    ++pszStart;

    char const     *pszEnd = pszAt + 1;

    for (; (*pszEnd != '\0') && (strchr("<> \t,\":;'\r\n", *pszEnd) == NULL); 
pszEnd++);

    int             iAddrLength = (int) (pszEnd - pszStart);

    strncpy(pszAddress, pszStart, iAddrLength);
    pszAddress[iAddrLength] = '\0';

    return (pszEnd);

}



static int      EmitRecipients(FILE * pMailFile, char const * pszAddrList)
{

    int             iRcptCount = 0;
    char const     *pszCurr = pszAddrList;

    for (; (pszCurr != NULL) && (*pszCurr != '\0');)
    {
        char const     *pszAt = strchr(pszCurr, '@');

        if (pszAt == NULL)
            break;


        char            szAddress[256] = "";

        if ((pszCurr = AddressFromAtPtr(pszAt, pszAddrList, szAddress)) != NULL)
        {
            fprintf(pMailFile, "rcpt to:<%s>\r\n", szAddress);

            ++iRcptCount;
        }

    }


    return (iRcptCount);

}



int             main(int iArgCount, char *pszArgs[])
{
///////////////////////////////////////////////////////////////////////////////
//  Get the mail root path
///////////////////////////////////////////////////////////////////////////////
    int             iVarLength = 0;
    FILE           *pInFile = stdin;
    char           *pszMailRoot = SysGetEnv(ENV_MAIL_ROOT);
    char            szMailRoot[SYS_MAX_PATH] = "";

    if ((pszMailRoot == NULL) || ((iVarLength = strlen(pszMailRoot)) == 0))
    {
        if (pszMailRoot != NULL)
            free(pszMailRoot);
        fprintf(stderr, "cannot find environment variable: %s\n", ENV_MAIL_ROOT);
        return (1);
    }

    strcpy(szMailRoot, pszMailRoot);

    if (szMailRoot[iVarLength - 1] != SYS_SLASH_CHAR)
        strcat(szMailRoot, SYS_SLASH_STR);

    free(pszMailRoot);

///////////////////////////////////////////////////////////////////////////////
//  Parse command line
///////////////////////////////////////////////////////////////////////////////
    int             ii;
    bool            bExtractRcpts = false,
                    bXMailFormat = false,
                    bDotMode = true;
    char            szMailFrom[256] = "",
                    szExtMailFrom[256] = "",
                    szInputFile[SYS_MAX_PATH] = "",
                    szRcptFile[SYS_MAX_PATH] = "";

    for (ii = 1; ii < iArgCount; ii++)
    {
        if (pszArgs[ii][0] != '-')
            break;

        if (strcmp(pszArgs[ii], "--") == 0)
        {
            ++ii;
            break;
        }

        if (pszArgs[ii][1] != '-')
        {
            int             iSkipParam = 0;
            bool            bEatAll = false;

            for (int jj = 1; !bEatAll && (pszArgs[ii][jj] != '\0'); jj++)
            {
                switch (pszArgs[ii][jj])
                {
                    case ('N'):
                    case ('O'):
                    case ('o'):
                    case ('R'):
                    case ('V'):
                    case ('X'):
                        iSkipParam = 1;
                        break;

                    case ('i'):
                        bDotMode = false;
                        break;

                    case ('t'):
                        bExtractRcpts = true;
                        break;

                    case ('f'):
                        StrSNCpy(szMailFrom, pszArgs[ii] + jj + 1);

                        bEatAll = true;
                        break;

                    case ('F'):
                        {
                            StrSNCpy(szExtMailFrom, pszArgs[ii] + jj + 1);

                            char const     *pszOpen = strchr(pszArgs[ii] + jj + 1, 
'<');

                            if (pszOpen == NULL)
                                StrSNCpy(szMailFrom, pszArgs[ii] + jj + 1);
                            else
                            {
                                StrSNCpy(szMailFrom, pszOpen + 1);

                                char           *pszClose = (char *) strchr(szMailFrom, 
'>');

                                if (pszClose != NULL)
                                    *pszClose = '\0';
                            }

                            bEatAll = true;
                        }
                        break;
                }
            }

            if (iSkipParam)
                ++ii;
        }
        else
        {
            if (strcmp(pszArgs[ii], "--rcpt-file") == 0)
            {
                if (++ii < iArgCount)
                    StrSNCpy(szRcptFile, pszArgs[ii]);
            }
            else if (strcmp(pszArgs[ii], "--xinput-file") == 0)
            {
                if (++ii < iArgCount)
                {
                    StrSNCpy(szInputFile, pszArgs[ii]);

                    bXMailFormat = true;
                }
            }
            else if (strcmp(pszArgs[ii], "--input-file") == 0)
            {
                if (++ii < iArgCount)
                    StrSNCpy(szInputFile, pszArgs[ii]);
            }
        }

    }

///////////////////////////////////////////////////////////////////////////////
//  Check if recipients are supplied
///////////////////////////////////////////////////////////////////////////////
    if (!bExtractRcpts && (ii >= iArgCount) && IsEmptyString(szRcptFile))
    {
        fprintf(stderr, "empty recipient list\n");
        return (2);
    }

    if (!IsEmptyString(szInputFile))
    {
        if ((pInFile = fopen(szInputFile, "rb")) == NULL)
        {
            perror(szInputFile);
            return (3);
        }
    }

///////////////////////////////////////////////////////////////////////////////
//  Save recipients index
///////////////////////////////////////////////////////////////////////////////
    int             iRcptIndex = ii,
                    iRcptCount = iArgCount - iRcptIndex;

///////////////////////////////////////////////////////////////////////////////
//  Create file name
///////////////////////////////////////////////////////////////////////////////
    char            szHostName[256] = "",
                    szDataFile[SYS_MAX_PATH] = "",
                    szMailFile[SYS_MAX_PATH] = "";

    SysGetHostName(szHostName, sizeof(szHostName) - 1);

    sprintf(szDataFile, "%s%s%lu.%lu.%s",
            szMailRoot,
            LOCAL_TEMP_SUBPATH,
            (unsigned long) time(NULL) * 1000,
            SysGetProcessId(),
            szHostName);

    sprintf(szMailFile, "%s.mail", szDataFile);

///////////////////////////////////////////////////////////////////////////////
//  Open raw data file
///////////////////////////////////////////////////////////////////////////////
    FILE           *pDataFile = fopen(szDataFile, "w+b");

    if (pDataFile == NULL)
    {
        perror(szDataFile);
        if (pInFile != stdin) fclose(pInFile);
        return (4);
    }

///////////////////////////////////////////////////////////////////////////////
//  Open maildrop file
///////////////////////////////////////////////////////////////////////////////
    FILE           *pMailFile = fopen(szMailFile, "wb");

    if (pMailFile == NULL)
    {
        perror(szMailFile);
        fclose(pDataFile), remove(szDataFile);
        if (pInFile != stdin) fclose(pInFile);
        return (5);
    }

///////////////////////////////////////////////////////////////////////////////
//  Emit sender
///////////////////////////////////////////////////////////////////////////////
    fprintf(pMailFile, "mail from:<%s>\r\n", szMailFrom);

///////////////////////////////////////////////////////////////////////////////
//  Emit recipients
///////////////////////////////////////////////////////////////////////////////
    for (ii = iRcptIndex; ii < iArgCount; ii++)
        fprintf(pMailFile, "rcpt to:<%s>\r\n", pszArgs[ii]);

///////////////////////////////////////////////////////////////////////////////
//  Emit message by reading from stdin
///////////////////////////////////////////////////////////////////////////////
    bool            bInHeaders = true,
                    bHasFrom = false,
                    bRcptSource = false;
    char            szBuffer[1536] = "";

    while (fgets(szBuffer, sizeof(szBuffer) - 1, pInFile) != NULL)
    {
        int             iLineLength = strlen(szBuffer);

        for (;(iLineLength > 0) &&
                ((szBuffer[iLineLength - 1] == '\r') || (szBuffer[iLineLength - 1] == 
'\n')); iLineLength--);

        szBuffer[iLineLength] = '\0';

///////////////////////////////////////////////////////////////////////////////
//  Is it time to stop reading ?
///////////////////////////////////////////////////////////////////////////////
        if (bDotMode && (strcmp(szBuffer, ".") == 0))
            break;

///////////////////////////////////////////////////////////////////////////////
//  Decode XMail spool file format
///////////////////////////////////////////////////////////////////////////////
        if (bXMailFormat)
        {
            if (strcmp(szBuffer, MAIL_DATA_TAG) == 0)
                bXMailFormat = false;

            continue;
        }

///////////////////////////////////////////////////////////////////////////////
//  Extract mail from
///////////////////////////////////////////////////////////////////////////////
        if (bInHeaders)
        {
            if (iLineLength == 0)
            {
                bInHeaders = false;

                if (!bHasFrom)
                {
///////////////////////////////////////////////////////////////////////////////
//  Add mail from ( if not present )
///////////////////////////////////////////////////////////////////////////////
                    if (strlen(szExtMailFrom) != 0)
                        fprintf(pDataFile, "From: %s\r\n", szExtMailFrom);
                    else
                        fprintf(pDataFile, "From: <%s>\r\n", szMailFrom);
                }
            }


            if ((szBuffer[0] == ' ') || (szBuffer[0] == '\t'))
            {
                if (bExtractRcpts && bRcptSource)
                {
                    int             iRcptCurr = EmitRecipients(pMailFile, szBuffer);

                    if (iRcptCurr > 0)
                        iRcptCount += iRcptCurr;
                }
            }
            else
            {
                bRcptSource = (strnicmp(szBuffer, "To:", 3) == 0) ||
                        (strnicmp(szBuffer, "Cc:", 3) == 0) ||
                        (strnicmp(szBuffer, "Bcc:", 4) == 0);

                if (bExtractRcpts && bRcptSource)
                {
                    int             iRcptCurr = EmitRecipients(pMailFile, szBuffer);

                    if (iRcptCurr > 0)
                        iRcptCount += iRcptCurr;
                }

                if (!bHasFrom && (strnicmp(szBuffer, "From:", 5) == 0))
                    bHasFrom = true;
            }
        }

///////////////////////////////////////////////////////////////////////////////
//  Emit mail line
///////////////////////////////////////////////////////////////////////////////
        fprintf(pDataFile, "%s\r\n", szBuffer);

    }

///////////////////////////////////////////////////////////////////////////////
//  Close input file if different from stdin
///////////////////////////////////////////////////////////////////////////////
    if (pInFile != stdin) fclose(pInFile);

///////////////////////////////////////////////////////////////////////////////
//  Dump recipient file
///////////////////////////////////////////////////////////////////////////////
    if (!IsEmptyString(szRcptFile))
    {
        FILE           *pRcptFile = SafeOpenFile(szRcptFile, "rb");

        if (pRcptFile == NULL)
        {
            perror(szRcptFile);
            fclose(pDataFile), remove(szDataFile);
            fclose(pMailFile), remove(szMailFile);
            return (6);
        }

        while (fgets(szBuffer, sizeof(szBuffer) - 1, pRcptFile) != NULL)
        {
            int             iLineLength = strlen(szBuffer);

            for (;(iLineLength > 0) &&
                    ((szBuffer[iLineLength - 1] == '\r') || (szBuffer[iLineLength - 1] 
== '\n')); iLineLength--);

            szBuffer[iLineLength] = '\0';

            if (iLineLength >= MAX_ADDR_NAME)
                continue;

            char           *pszAt = strchr(szBuffer, '@');

            if (pszAt == NULL)
                continue;

            char            szRecipient[MAX_ADDR_NAME] = "";

            if (AddressFromAtPtr(pszAt, szBuffer, szRecipient) != NULL)
            {
                fprintf(pMailFile, "rcpt to:<%s>\r\n", szRecipient);

                ++iRcptCount;
            }
        }

        fclose(pRcptFile);
    }

///////////////////////////////////////////////////////////////////////////////
//  Check the number of recipients
///////////////////////////////////////////////////////////////////////////////
    if (iRcptCount == 0)
    {
        fprintf(stderr, "empty recipient list\n");
        fclose(pDataFile), remove(szDataFile);
        fclose(pMailFile), remove(szMailFile);
        return (7);
    }

///////////////////////////////////////////////////////////////////////////////
//  Empty line separator between maildrop header and data
///////////////////////////////////////////////////////////////////////////////
    fprintf(pMailFile, "\r\n");

///////////////////////////////////////////////////////////////////////////////
//  Append data file
///////////////////////////////////////////////////////////////////////////////
    rewind(pDataFile);

    unsigned int    uReaded;

    do
    {
        if (((uReaded = fread(szBuffer, 1, sizeof(szBuffer), pDataFile)) != 0) &&
                (fwrite(szBuffer, 1, uReaded, pMailFile) != uReaded))
        {
            perror(szMailFile);
            fclose(pDataFile), remove(szDataFile);
            fclose(pMailFile), remove(szMailFile);
            return (8);
        }

    } while (uReaded == sizeof(szBuffer));

    fclose(pDataFile), remove(szDataFile);

///////////////////////////////////////////////////////////////////////////////
//  Sync and close the mail file
///////////////////////////////////////////////////////////////////////////////
    if ((SysFileSync(pMailFile) < 0) || fclose(pMailFile))
    {
        remove(szMailFile);
        fprintf(stderr, "cannot write file: %s\n", szMailFile);
        return (9);
    }

///////////////////////////////////////////////////////////////////////////////
//  Move the mail file
///////////////////////////////////////////////////////////////////////////////
    char            szDropFile[SYS_MAX_PATH] = "";

    sprintf(szDropFile, "%s%s%lu.%lu.%s",
            szMailRoot,
            LOCAL_SUBPATH,
            (unsigned long) time(NULL) * 1000,
            SysGetProcessId(),
            szHostName);

    if (SysMoveFile(szMailFile, szDropFile) < 0)
    {
        remove(szMailFile);
        fprintf(stderr, "cannot move file: %s\n", szMailFile);
        return (10);
    }


    return (0);

}

-
To unsubscribe from this list: send the line "unsubscribe xmail" in
the body of a message to [EMAIL PROTECTED]
For general help: send the line "help" in the body of a message to
[EMAIL PROTECTED]

Reply via email to