fixed mail sender address encoding
authorVictor Kirhenshtein <victor@netxms.org>
Tue, 22 Aug 2017 17:20:08 +0000 (20:20 +0300)
committerVictor Kirhenshtein <victor@netxms.org>
Tue, 22 Aug 2017 17:20:08 +0000 (20:20 +0300)
ChangeLog
src/server/core/email.cpp

index 8bbe434..16c389d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -16,6 +16,7 @@
 - Fixed OpenBSD compatibility issues
 - Correct handling of "dormant" and "not present" interface operational states
 - Syslog messages received on loopback bound to receiving node (local management node or syslog proxy node)
+- Fixed mail sender address encoding
 - NXSL:
        - New class "InetAddress"
        - New attribute "ipAddressList" for class "Interface"
index 5f89711..6744634 100644 (file)
@@ -58,16 +58,13 @@ struct MAIL_ENVELOPE
    char *text;
    char encoding[64];
    bool isHtml;
+   bool isUtf8;
    int retryCount;
 };
 
 /**
  * Static data
  */
-static TCHAR m_szSmtpServer[MAX_PATH] = _T("localhost");
-static WORD m_wSmtpPort = 25;
-static char m_szFromAddr[MAX_PATH] = "netxms@localhost";
-static char m_szFromName[MAX_PATH] = "NetXMS Server";
 static Queue *m_pMailerQueue = NULL;
 static THREAD m_hThread = INVALID_THREAD_HANDLE;
 
@@ -133,33 +130,90 @@ static int GetSMTPResponse(SOCKET hSocket, char *pszBuffer, int *pnBufPos)
 }
 
 /**
+ * Encode SMTP header
+ */
+static char *EncodeHeader(const char *header, const char *encoding, const char *data, char *buffer, size_t bufferSize)
+{
+   bool encode = false;
+   for(const char *p = data; *p != 0; p++)
+      if (*p & 0x80)
+      {
+         encode = true;
+         break;
+      }
+   if (encode)
+   {
+      char *encodedData = NULL;
+      base64_encode_alloc(data, strlen(data), &encodedData);
+      if (encodedData != NULL)
+      {
+         if (header != NULL)
+            snprintf(buffer, bufferSize, "%s: =?%s?B?%s?=\r\n", header, encoding, encodedData);
+         else
+            snprintf(buffer, bufferSize, "=?%s?B?%s?=", encoding, encodedData);
+         free(encodedData);
+      }
+      else
+      {
+         // fallback
+         if (header != NULL)
+            snprintf(buffer, bufferSize, "%s: %s\r\n", header, data);
+         else
+            strncpy(buffer, data, bufferSize);
+      }
+   }
+   else
+   {
+      if (header != NULL)
+         snprintf(buffer, bufferSize, "%s: %s\r\n", header, data);
+      else
+         strncpy(buffer, data, bufferSize);
+   }
+   return buffer;
+}
+
+/**
  * Send e-mail
  */
-static UINT32 SendMail(const char *pszRcpt, const char *pszSubject, const char *pszText, const char *encoding, bool isHtml)
+static UINT32 SendMail(const char *pszRcpt, const char *pszSubject, const char *pszText, const char *encoding, bool isHtml, bool isUtf8)
 {
-   SOCKET hSocket;
-   char szBuffer[SMTP_BUFFER_SIZE];
-   int iResp, iState = STATE_INITIAL, nBufPos = 0;
-   UINT32 dwRetCode;
+   TCHAR smtpServer[256];
+   char fromName[256], fromAddr[256];
+   ConfigReadStr(_T("SMTPServer"), smtpServer, 256, _T("localhost"));
+   ConfigReadStrA(_T("SMTPFromAddr"), fromAddr, 256, "netxms@localhost");
+   if (isUtf8)
+   {
+      ConfigReadStrUTF8(_T("SMTPFromName"), fromName, 256, "NetXMS Server");
+   }
+   else
+   {
+      ConfigReadStrA(_T("SMTPFromName"), fromName, 256, "NetXMS Server");
+   }
+   UINT16 smtpPort = (UINT16)ConfigReadInt(_T("SMTPPort"), 25);
 
    // Resolve hostname
-       InetAddress addr = InetAddress::resolveHostName(m_szSmtpServer);
+       InetAddress addr = InetAddress::resolveHostName(smtpServer);
    if (!addr.isValid() || addr.isBroadcast() || addr.isMulticast())
       return SMTP_ERR_BAD_SERVER_NAME;
 
    // Create socket
-   hSocket = socket(addr.getFamily(), SOCK_STREAM, 0);
+   SOCKET hSocket = socket(addr.getFamily(), SOCK_STREAM, 0);
    if (hSocket == INVALID_SOCKET)
       return SMTP_ERR_COMM_FAILURE;
 
+   UINT32 dwRetCode;
+
    // Connect to server
    SockAddrBuffer sa;
-   addr.fillSockAddr(&sa, m_wSmtpPort);
+   addr.fillSockAddr(&sa, smtpPort);
    if (ConnectEx(hSocket, (struct sockaddr *)&sa, SA_LEN((struct sockaddr *)&sa), 3000) == 0)
    {
+      char szBuffer[SMTP_BUFFER_SIZE];
+      int nBufPos = 0;
+      int iState = STATE_INITIAL;
       while((iState != STATE_FINISHED) && (iState != STATE_ERROR))
       {
-         iResp = GetSMTPResponse(hSocket, szBuffer, &nBufPos);
+         int iResp = GetSMTPResponse(hSocket, szBuffer, &nBufPos);
                        DbgPrintf(8, _T("SMTP RESPONSE: %03d (state=%d)"), iResp, iState);
          if (iResp > 0)
          {
@@ -182,7 +236,7 @@ static UINT32 SendMail(const char *pszRcpt, const char *pszSubject, const char *
                   if (iResp == 250)
                   {
                      iState = STATE_FROM;
-                     snprintf(szBuffer, SMTP_BUFFER_SIZE, "MAIL FROM: <%s>\r\n", m_szFromAddr);
+                     snprintf(szBuffer, SMTP_BUFFER_SIZE, "MAIL FROM: <%s>\r\n", fromAddr);
                      SendEx(hSocket, szBuffer, strlen(szBuffer), 0, NULL);
                   }
                   else
@@ -223,38 +277,14 @@ static UINT32 SendMail(const char *pszRcpt, const char *pszSubject, const char *
 
                      // Mail headers
                      // from
-                     snprintf(szBuffer, SMTP_BUFFER_SIZE, "From: %s <%s>\r\n", m_szFromName, m_szFromAddr);
+                     char from[512];
+                     snprintf(szBuffer, SMTP_BUFFER_SIZE, "From: \"%s\" <%s>\r\n", EncodeHeader(NULL, encoding, fromName, from, 512), fromAddr);
                      SendEx(hSocket, szBuffer, strlen(szBuffer), 0, NULL);
                      // to
                      snprintf(szBuffer, SMTP_BUFFER_SIZE, "To: <%s>\r\n", pszRcpt);
                      SendEx(hSocket, szBuffer, strlen(szBuffer), 0, NULL);
                      // subject
-                     bool encodeSubject = false;
-                     for(const char *p = pszSubject; *p != 0; p++)
-                        if (*p & 0x80)
-                        {
-                           encodeSubject = true;
-                           break;
-                        }
-                     if (encodeSubject)
-                     {
-                        char *encodedSubject = NULL;
-                        base64_encode_alloc(pszSubject, strlen(pszSubject), &encodedSubject);
-                        if (encodedSubject != NULL)
-                        {
-                           snprintf(szBuffer, SMTP_BUFFER_SIZE, "Subject: =?%s?B?%s?=\r\n", encoding, encodedSubject);
-                           free(encodedSubject);
-                        }
-                        else
-                        {
-                           // fallback
-                           snprintf(szBuffer, SMTP_BUFFER_SIZE, "Subject: %s\r\n", pszSubject);
-                        }
-                     }
-                     else
-                     {
-                        snprintf(szBuffer, SMTP_BUFFER_SIZE, "Subject: %s\r\n", pszSubject);
-                     }
+                     EncodeHeader("Subject", encoding, pszSubject, szBuffer, SMTP_BUFFER_SIZE);
                      SendEx(hSocket, szBuffer, strlen(szBuffer), 0, NULL);
                      
                                                        // date
@@ -383,14 +413,9 @@ static THREAD_RESULT THREAD_CALL MailerThread(void *pArg)
       if (pEnvelope == INVALID_POINTER_VALUE)
          break;
 
-               DbgPrintf(6, _T("SMTP(%p): new envelope, rcpt=%hs"), pEnvelope, pEnvelope->rcptAddr);
-
-      ConfigReadStr(_T("SMTPServer"), m_szSmtpServer, MAX_PATH, _T("localhost"));
-      ConfigReadStrA(_T("SMTPFromAddr"), m_szFromAddr, MAX_PATH, "netxms@localhost");
-      ConfigReadStrA(_T("SMTPFromName"), m_szFromName, MAX_PATH, "NetXMS Server");
-      m_wSmtpPort = (WORD)ConfigReadInt(_T("SMTPPort"), 25);
+               nxlog_debug(6, _T("SMTP(%p): new envelope, rcpt=%hs"), pEnvelope, pEnvelope->rcptAddr);
 
-      UINT32 dwResult = SendMail(pEnvelope->rcptAddr, pEnvelope->subject, pEnvelope->text, pEnvelope->encoding, pEnvelope->isHtml);
+      UINT32 dwResult = SendMail(pEnvelope->rcptAddr, pEnvelope->subject, pEnvelope->text, pEnvelope->encoding, pEnvelope->isHtml, pEnvelope->isUtf8);
       if (dwResult != SMTP_ERR_SUCCESS)
                {
                        pEnvelope->retryCount--;
@@ -446,16 +471,16 @@ void NXCORE_EXPORTABLE PostMail(const TCHAR *pszRcpt, const TCHAR *pszSubject, c
 {
    MAIL_ENVELOPE *envelope = (MAIL_ENVELOPE *)malloc(sizeof(MAIL_ENVELOPE));
    ConfigReadStrA(_T("MailEncoding"), envelope->encoding, 64, "utf8");
-   bool isUtf8 = isHtml ||!stricmp(envelope->encoding, "utf-8") || !stricmp(envelope->encoding, "utf8");
+   envelope->isUtf8 = isHtml || !stricmp(envelope->encoding, "utf-8") || !stricmp(envelope->encoding, "utf8");
 
 #ifdef UNICODE
-       WideCharToMultiByte(isUtf8 ? CP_UTF8 : CP_ACP, isUtf8 ? 0 : WC_DEFAULTCHAR | WC_COMPOSITECHECK, pszRcpt, -1, envelope->rcptAddr, MAX_RCPT_ADDR_LEN, NULL, NULL);
+       WideCharToMultiByte(envelope->isUtf8 ? CP_UTF8 : CP_ACP, envelope->isUtf8 ? 0 : WC_DEFAULTCHAR | WC_COMPOSITECHECK, pszRcpt, -1, envelope->rcptAddr, MAX_RCPT_ADDR_LEN, NULL, NULL);
        envelope->rcptAddr[MAX_RCPT_ADDR_LEN - 1] = 0;
-       WideCharToMultiByte(isUtf8 ? CP_UTF8 : CP_ACP, isUtf8 ? 0 : WC_DEFAULTCHAR | WC_COMPOSITECHECK, pszSubject, -1, envelope->subject, MAX_EMAIL_SUBJECT_LEN, NULL, NULL);
+       WideCharToMultiByte(envelope->isUtf8 ? CP_UTF8 : CP_ACP, envelope->isUtf8 ? 0 : WC_DEFAULTCHAR | WC_COMPOSITECHECK, pszSubject, -1, envelope->subject, MAX_EMAIL_SUBJECT_LEN, NULL, NULL);
        envelope->subject[MAX_EMAIL_SUBJECT_LEN - 1] = 0;
-       envelope->text = isUtf8 ? UTF8StringFromWideString(pszText) : MBStringFromWideString(pszText);
+       envelope->text = envelope->isUtf8 ? UTF8StringFromWideString(pszText) : MBStringFromWideString(pszText);
 #else
-       if (isUtf8)
+       if (envelope->isUtf8)
        {
           mb_to_utf8(pszRcpt, -1, envelope->rcptAddr, MAX_RCPT_ADDR_LEN);
           envelope->rcptAddr[MAX_RCPT_ADDR_LEN - 1] = 0;