From 825de608dfdf4f65f80e447a0dd9408a484ae1e7 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Fri, 16 Oct 2009 11:59:18 +0000 Subject: [PATCH] 2009-10-16 13:54 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * contrib/hbtip/sendmail.prg * contrib/hbtip/mail.prg ! Fixed encoding of subject, from, to, cc, bcc address lists, in some places it was missing (cc, bcc, from), in some other places multiple address support was missing (to, cc, bcc) from recent addition of encoding support. + Added/Fixed support for human readable name component in e-mail addresses. + Using TIPMAIL:SETHEADER() in HB_SENDMAIL() to set above header components. ! Several minor cleanups in TIPMAIL:SETHEADER(): - handling of empty values - using space instead of tab when passing multiple addresses in headers. Haven't checked the standard, but I used to see space there. - Minor formatting, optimizations. ! Minor tweaks to space and _ char in Q encoding. Now they are both simply encoded. ; Overall probably a rewrite would be the best in case of hbtip mailing, and maybe not just for mailing. Code is full of strange tweaks, redundancy and the class layout/communication is rather strange, f.e. SMTP protocol data is passed via TURL:cFile variable from HB_SENDMAIL to SMTP client class. Also charset support is just an aftertought so user code needs close syncronisation with HB_SENDMAIL() and replicating the same parameter parsing logic on multiple layers of code. And I've probably just scratched the surface, f.e. I didn't test attachments of HTML mails and probably several other options as well. ; Anyway please test. --- harbour/ChangeLog | 27 +++++++++ harbour/contrib/hbtip/mail.prg | 95 +++++++++++++++++------------- harbour/contrib/hbtip/sendmail.prg | 87 ++++++++++++++------------- 3 files changed, 123 insertions(+), 86 deletions(-) diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 3a9947a78a..dd856e4d52 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,33 @@ past entries belonging to author(s): Viktor Szakats. */ +2009-10-16 13:54 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) + * contrib/hbtip/sendmail.prg + * contrib/hbtip/mail.prg + ! Fixed encoding of subject, from, to, cc, bcc address lists, in some + places it was missing (cc, bcc, from), in some other places multiple + address support was missing (to, cc, bcc) from recent addition of + encoding support. + + Added/Fixed support for human readable name component in e-mail addresses. + + Using TIPMAIL:SETHEADER() in HB_SENDMAIL() to set above header components. + ! Several minor cleanups in TIPMAIL:SETHEADER(): + - handling of empty values + - using space instead of tab when passing multiple addresses in headers. + Haven't checked the standard, but I used to see space there. + - Minor formatting, optimizations. + ! Minor tweaks to space and _ char in Q encoding. Now + they are both simply encoded. + ; Overall probably a rewrite would be the best in case of hbtip mailing, + and maybe not just for mailing. Code is full of strange tweaks, + redundancy and the class layout/communication is rather strange, f.e. + SMTP protocol data is passed via TURL:cFile variable from HB_SENDMAIL + to SMTP client class. Also charset support is just an aftertought so + user code needs close syncronisation with HB_SENDMAIL() and replicating + the same parameter parsing logic on multiple layers of code. + And I've probably just scratched the surface, f.e. I didn't test + attachments of HTML mails and probably several other options as well. + ; Anyway please test. + 2009-10-15 18:43 UTC-0800 Pritpal Bedi (pritpal@vouchcac.com) * contrib/hbqt/generator/hbqtgen.prg ! Changes to implemented GC pointers. diff --git a/harbour/contrib/hbtip/mail.prg b/harbour/contrib/hbtip/mail.prg index 18b6ab907f..471cb34955 100644 --- a/harbour/contrib/hbtip/mail.prg +++ b/harbour/contrib/hbtip/mail.prg @@ -313,13 +313,13 @@ METHOD ToString() CLASS TipMail cRet += "Date: " + ::hHeaders[ "Date" ] + e"\r\n" ENDIF IF "From" $ ::hHeaders - cRet += "From: " + LTrim( WordEncodeQ( tip_GetNameEMail( ::hHeaders[ "From" ] ), ::cCharset ) + " <" + tip_GetRawEMail( ::hHeaders[ "From" ] ) + ">" ) + e"\r\n" + cRet += "From: " + ::hHeaders[ "From" ] + e"\r\n" ENDIF IF "To" $ ::hHeaders - cRet += "To: " + LTrim( WordEncodeQ( tip_GetNameEMail( ::hHeaders[ "To" ] ), ::cCharset ) + " <" + tip_GetRawEMail( ::hHeaders[ "To" ] ) + ">" ) + e"\r\n" + cRet += "To: " + ::hHeaders[ "To" ] + e"\r\n" ENDIF IF "Subject" $ ::hHeaders - cRet += "Subject: " + WordEncodeQ( ::hHeaders[ "Subject" ], ::cCharset ) + e"\r\n" + cRet += "Subject: " + ::hHeaders[ "Subject" ] + e"\r\n" ENDIF IF Len( ::aAttachments ) > 0 cRet += "Mime-Version:" + ::hHeaders[ "Mime-Version" ] + e"\r\n" @@ -513,8 +513,9 @@ METHOD MakeBoundary() CLASS TipMail RETURN cBound -METHOD setHeader( cSubject, cFrom, cTo, cCC, cBCC ) CLASS TipMail +METHOD setHeader( cSubject, cFrom, xTo, xCC, xBCC ) CLASS TipMail LOCAL aTo, aCC, aBCC, i, imax + LOCAL cTo, cCC, cBCC IF ! ISCHARACTER( cSubject ) cSubject := "" @@ -524,66 +525,79 @@ METHOD setHeader( cSubject, cFrom, cTo, cCC, cBCC ) CLASS TipMail RETURN .F. ENDIF - IF ISCHARACTER( cTo ) - aTo := { cTo } - ELSEIF ISARRAY( cTo ) - aTo := cTo + IF ISCHARACTER( xTo ) + aTo := { xTo } + ELSEIF ISARRAY( xTo ) + aTo := xTo ENDIF - IF ISCHARACTER( cCC ) - aCC := { cCC } - ELSEIF ISARRAY( cCC ) - aCC := cCC - ENDIF - - IF ISCHARACTER( cBCC ) - aBCC := { cBCC } - ELSEIF ISARRAY( cBCC ) - aBCC := cBCC - ENDIF - - IF aTO == NIL + IF Empty( aTO ) RETURN .F. ENDIF - IF ! ::setFieldPart( "Subject", cSubject ) + IF ISCHARACTER( xCC ) + aCC := { xCC } + ELSEIF ISARRAY( xCC ) + aCC := xCC + ENDIF + + IF ISCHARACTER( xBCC ) + aBCC := { xBCC } + ELSEIF ISARRAY( xBCC ) + aBCC := xBCC + ENDIF + + IF ! ::setFieldPart( "Subject", WordEncodeQ( cSubject, ::cCharset ) ) + RETURN .F. + ENDIF + + IF ! ::setFieldPart( "From", LTrim( WordEncodeQ( tip_GetNameEMail( AllTrim( cFrom ) ), ::cCharset ) + " <" + tip_GetRawEMail( AllTrim( cFrom ) ) + ">" ) ) RETURN .F. ENDIF - IF ! ::setFieldPart( "From", cFrom ) - RETURN .F. - ENDIF - - cTo := aTO[ 1 ] + cTo := "" imax := Len( aTO ) - FOR i := 2 TO imax - cTo += "," + hb_inetCrlf() + Chr( 9 ) + aTo[ i ] + FOR i := 1 TO imax + IF i > 1 + cTo += "," + hb_inetCrlf() + " " + ENDIF + cTo += LTrim( WordEncodeQ( tip_GetNameEMail( AllTrim( aTo[ i ] ) ), ::cCharset ) + " <" + tip_GetRawEMail( AllTrim( aTo[ i ] ) ) + ">" ) NEXT + IF Empty( cTo ) + RETURN .F. + ENDIF + IF ! ::setFieldPart( "To", cTo ) RETURN .F. ENDIF - IF aCC != NIL - cCC := aCC[ 1 ] + IF ! Empty( aCC ) + cCC := "" imax := Len( aCC ) FOR i := 2 TO imax - cCC += "," + hb_inetCrlf() + Chr( 9 ) + aCC[ i ] + IF i > 1 + cCC += "," + hb_inetCrlf() + " " + ENDIF + cCC += LTrim( WordEncodeQ( tip_GetNameEMail( AllTrim( aCC[ i ] ) ), ::cCharset ) + " <" + tip_GetRawEMail( AllTrim( aCC[ i ] ) ) + ">" ) NEXT - IF ! ::setFieldPart( "Cc", cCC ) + IF ! Empty( cCC ) .AND. ! ::setFieldPart( "Cc", cCC ) RETURN .F. ENDIF ENDIF - IF aBCC != NIL - cBCC := aBCC[ 1 ] + IF ! Empty( aBCC ) + cBCC := "" imax := Len( aBCC ) FOR i := 2 TO imax - cBCC += "," + hb_inetCrlf() + Chr( 9 ) + aBCC[ i ] + IF i > 1 + cBCC += "," + hb_inetCrlf() + " " + ENDIF + cBCC += LTrim( WordEncodeQ( tip_GetNameEMail( AllTrim( aBCC[ i ] ) ), ::cCharset ) + " <" + tip_GetRawEMail( AllTrim( aBCC[ i ] ) ) + ">" ) NEXT - IF ! ::setFieldPart( "Bcc", cBCC ) + IF ! Empty( cBCC ) .AND. ! ::setFieldPart( "Bcc", cBCC ) RETURN .F. ENDIF ENDIF @@ -678,11 +692,8 @@ STATIC FUNCTION WordEncodeQ( cData, cCharset ) cString := "=?" + cCharset + "?" + "Q" + "?" FOR EACH c IN cData - IF c == " " - cString += "_" - nLineLen += 1 - ELSEIF Asc( c ) > 126 .OR. ; - c $ '=?!"#$@[\]^`{|}~' .OR. ; + IF Asc( c ) > 126 .OR. ; + c $ '=?!"#$@[\]^`{|}~_' .OR. ; Asc( c ) <= 32 cString += "=" + hb_NumToHex( Asc( c ), 2 ) nLineLen += 3 diff --git a/harbour/contrib/hbtip/sendmail.prg b/harbour/contrib/hbtip/sendmail.prg index fb3022b976..f2b03a1ef6 100644 --- a/harbour/contrib/hbtip/sendmail.prg +++ b/harbour/contrib/hbtip/sendmail.prg @@ -55,14 +55,14 @@ #translate ( LIKE ) => ( hb_regexLike( (), () ) ) -FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aFiles, cUser, cPass, cPopServer, nPriority, lRead, bTrace, lPopAuth, lNoAuth, nTimeOut, cReplyTo, lTLS, cSMTPPass, cCharset, cEncoding ) +FUNCTION hb_SendMail( cServer, nPort, cFrom, xTo, xCC, xBCC, cBody, cSubject, aFiles, cUser, cPass, cPopServer, nPriority, lRead, bTrace, lPopAuth, lNoAuth, nTimeOut, cReplyTo, lTLS, cSMTPPass, cCharset, cEncoding ) /* cServer -> Required. IP or domain name of the mail server nPort -> Optional. Port used my email server cFrom -> Required. Email address of the sender - aTo -> Required. Character string or array of email addresses to send the email to - aCC -> Optional. Character string or array of email adresses for CC (Carbon Copy) - aBCC -> Optional. Character string or array of email adresses for BCC (Blind Carbon Copy) + xTo -> Required. Character string or array of email addresses to send the email to + xCC -> Optional. Character string or array of email adresses for CC (Carbon Copy) + xBCC -> Optional. Character string or array of email adresses for BCC (Blind Carbon Copy) cBody -> Optional. The body message of the email as text, or the filename of the HTML message to send. cSubject -> Optional. Subject of the sending email aFiles -> Optional. Array of attachments to the email to send @@ -79,8 +79,18 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF cReplyTo -> Optional. */ - LOCAL oInMail, cBodyTemp, oUrl, oMail, oAttach, aThisFile, cMimeText,; - cFile, cFname, cFext, cData, oUrl1 + LOCAL oInMail + LOCAL cBodyTemp + LOCAL oUrl + LOCAL oMail + LOCAL oAttach + LOCAL aThisFile + LOCAL cMimeText + LOCAL cFile + LOCAL cFname + LOCAL cFext + LOCAL cData + LOCAL oUrl1 LOCAL cTmp := "" LOCAL cTo := "" @@ -154,53 +164,53 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF ENDIF // cTo - IF ISARRAY( aTo ) - IF Len( aTo ) > 1 - FOR EACH cTo IN aTo + IF ISARRAY( xTo ) + IF Len( xTo ) > 1 + FOR EACH cTo IN xTo IF cTo:__enumIndex() != 1 IF ! Empty( cTo ) - cTmp += cTo + "," + cTmp += tip_GetRawEMail( AllTrim( cTo ) ) + "," ENDIF ENDIF NEXT cTmp := SubStr( cTmp, 1, Len( cTmp ) - 1 ) ENDIF - cTo := aTo[ 1 ] + cTo := tip_GetRawEMail( AllTrim( xTo[ 1 ] ) ) IF Len( cTmp ) > 0 cTo += "," + cTmp ENDIF - ELSEIF ISCHARACTER( aTo ) - cTo := AllTrim( aTo ) + ELSEIF ISCHARACTER( xTo ) + cTo := tip_GetRawEMail( AllTrim( xTo ) ) ENDIF // CC (Carbon Copy) - IF ISARRAY( aCC ) - IF Len( aCC ) > 0 - FOR EACH cTmp IN aCC + IF ISARRAY( xCC ) + IF Len( xCC ) > 0 + FOR EACH cTmp IN xCC IF ! Empty( cTmp ) - cCC += cTmp + "," + cCC += tip_GetRawEMail( AllTrim( cTmp ) ) + "," ENDIF NEXT cCC := SubStr( cCC, 1, Len( cCC ) - 1 ) ENDIF - ELSEIF ISCHARACTER( aCC ) - cCC := AllTrim( aCC ) + ELSEIF ISCHARACTER( xCC ) + cCC := tip_GetRawEMail( AllTrim( xCC ) ) ENDIF // BCC (Blind Carbon Copy) - IF ISARRAY( aBCC ) - IF Len( aBCC ) > 0 - FOR EACH cTmp IN aBCC + IF ISARRAY( xBCC ) + IF Len( xBCC ) > 0 + FOR EACH cTmp IN xBCC IF ! Empty( cTmp ) - cBCC += cTmp + "," + cBCC += tip_GetRawEMail( AllTrim( cTmp ) ) + "," ENDIF NEXT cBCC := SubStr( cBCC, 1, Len( cBCC ) - 1 ) ENDIF - ELSEIF ISCHARACTER( aBCC ) - cBCC := AllTrim( aBCC ) + ELSEIF ISCHARACTER( xBCC ) + cBCC := tip_GetRawEMail( AllTrim( xBCC ) ) ENDIF IF cPopServer != NIL .AND. lPopAuth @@ -214,7 +224,6 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF RECOVER lReturn := .F. END SEQUENCE - ENDIF IF ! lReturn @@ -222,7 +231,7 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF ENDIF BEGIN SEQUENCE - oUrl := tUrl():New( iif( lTLS, "smtps://", "smtp://" ) + cUser + iif( Empty( cSMTPPass ), "", ":" + cSMTPPass ) + "@" + cServer + "/" + cTo ) + oUrl := tUrl():New( iif( lTLS, "smtps://", "smtp://" ) + cUser + iif( Empty( cSMTPPass ), "", ":" + cSMTPPass ) + "@" + cServer ) RECOVER lReturn := .F. END SEQUENCE @@ -237,6 +246,12 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF oMail := tipMail():new() oMail:SetEncoder( cEncoding ) oMail:SetCharset( cCharset ) + oMail:SetHeader( cSubject, cFrom, xTo, xCC, xBCC ) + oMail:hHeaders[ "Date" ] := tip_Timestamp() + IF ! Empty( cReplyTo ) + oMail:hHeaders[ "Reply-to" ] := cReplyTo + ENDIF + IF ! Empty( aFiles ) oAttach := tipMail():new() oAttach:SetEncoder( cEncoding ) @@ -266,19 +281,6 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF oUrl:cFile := cTo + iif( Empty( cCC ), "", "," + cCC ) + iif( Empty( cBCC ), "", "," + cBCC ) - oMail:hHeaders[ "Date" ] := tip_Timestamp() - oMail:hHeaders[ "From" ] := cFrom - - IF ! Empty( cReplyTo ) - oMail:hHeaders[ "Reply-to" ] := cReplyTo - ENDIF - IF ! Empty( cCC ) - oMail:hHeaders[ "Cc" ] := cCC - ENDIF - IF ! Empty( cBCC ) - oMail:hHeaders[ "Bcc" ] := cBCC - ENDIF - BEGIN SEQUENCE oInmail := tIPClientSMTP():New( oUrl, bTrace ) RECOVER @@ -369,9 +371,6 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF oInMail:oUrl:cUserid := cFromRaw - oMail:hHeaders[ "To" ] := cTo - oMail:hHeaders[ "Subject" ] := cSubject - FOR EACH aThisFile IN aFiles IF ISCHARACTER( aThisFile ) @@ -456,7 +455,7 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF oMail:hHeaders[ "X-Priority" ] := Str( nPriority, 1 ) ENDIF - oInmail:Write( oMail:ToString() ) + oInMail:Write( oMail:ToString() ) oInMail:Commit() oInMail:Close()