2009-07-24 09:40 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)

* contrib/hbtip/sendmail.prg
  * contrib/hbtip/client.prg
  * contrib/hbtip/smtpcln.prg
    + Added TLS (SMTPS, SSL) support for SMTP class. It's experimental
      yet, and there is still some protocol level error.
      With this it'll possible to send e-mails through gmail for
      example.
      Some level of STARTTLS support (TLS on normal SMTP ports)
      was also added, but I cannot test this.
      Anyhow from this point it should be an easy task to
      finish above details.
      Since TLS was added to low level client class, it's now
      possible to add SSL support also for POPS, HTTPS and FTPS.
    ; NOTE: This code part is only active if hbtip is built with 
            -DHAVE_OPENSSL build-time flag, and it also requires 
            hbssl lib + OpenSSL libs.

  * contrib/hbtip/utils.c
    ! Fixed timezone offset being always zero in TIP_TIMESTAMP()
This commit is contained in:
Viktor Szakats
2009-07-24 07:42:15 +00:00
parent 46c0860b3b
commit 347c39ae3c
5 changed files with 260 additions and 47 deletions

View File

@@ -17,6 +17,27 @@
past entries belonging to author(s): Viktor Szakats.
*/
2009-07-24 09:40 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
* contrib/hbtip/sendmail.prg
* contrib/hbtip/client.prg
* contrib/hbtip/smtpcln.prg
+ Added TLS (SMTPS, SSL) support for SMTP class. It's experimental
yet, and there is still some protocol level error.
With this it'll possible to send e-mails through gmail for
example.
Some level of STARTTLS support (TLS on normal SMTP ports)
was also added, but I cannot test this.
Anyhow from this point it should be an easy task to
finish above details.
Since TLS was added to low level client class, it's now
possible to add SSL support also for POPS, HTTPS and FTPS.
; NOTE: This code part is only active if hbtip is built with
-DHAVE_OPENSSL build-time flag, and it also requires
hbssl lib + OpenSSL libs.
* contrib/hbtip/utils.c
! Fixed timezone offset being always zero in TIP_TIMESTAMP()
2009-07-23 21:44 UTC+0200 Viktor Szakats (harbour.01 syenar.hu)
* contrib/rddads/ads1.c
! Reverted prev change plus added error handling. Thx Przemek.
@@ -65,6 +86,9 @@
* contrib/hbcurl/hbcurl.c
* contrib/hbwin/win_prt.c
! Fixed similar to above allocation errors.
CURL_EASY_RECV() in hbcurl.
WINPORTREAD() in hbwin.
HB_FREADLINE() in xhb.
* config/global.cf
+ Added HB_???_INSTALL initialization. Just a step, needs more

View File

@@ -73,6 +73,14 @@
#include "error.ch"
#include "fileio.ch"
#if defined( _SSL_DEBUG_TEMP )
#include "simpleio.ch"
#endif
#if defined( HAVE_OPENSSL )
#include "hbssl.ch"
#endif
#include "tip.ch"
#define RCV_BUF_SIZE Int( ::InetRcvBufSize( ::SocketCon ) / 2 )
@@ -114,6 +122,13 @@ CREATE CLASS tIPClient
VAR exGauge /* Gauge control; it can be a codeblock or a function pointer. */
VAR lTLS INIT .F.
#if defined( HAVE_OPENSSL )
VAR ssl_ctx
VAR ssl
VAR nSSLError INIT 0
#endif
VAR Cargo
/* Data for proxy connection */
@@ -125,6 +140,8 @@ CREATE CLASS tIPClient
METHOD New( oUrl, lTrace, oCredentials )
METHOD Open()
METHOD EnableTLS( lEnable )
METHOD Read( iLen )
METHOD ReadToFile( cFile, nMode, nSize )
METHOD Write( cData, iLen, bCommit )
@@ -138,7 +155,7 @@ CREATE CLASS tIPClient
METHOD SetProxy( cProxyHost, nProxyPort, cProxyUser, cProxyPassword )
METHOD lastErrorCode() INLINE ::nLastError
METHOD lastErrorMessage(SocketCon) INLINE ::INetErrorDesc(SocketCon)
METHOD lastErrorMessage( SocketCon ) INLINE ::INetErrorDesc( SocketCon )
METHOD InetRcvBufSize( SocketCon, nSizeBuff )
METHOD InetSndBufSize( SocketCon, nSizeBuff )
@@ -147,8 +164,8 @@ CREATE CLASS tIPClient
VAR nLastError INIT 0
METHOD OpenProxy( cServer, nPort, cProxy, nProxyPort, cResp, cUserName, cPassWord, nTimeOut, cUserAgent )
METHOD ReadHTTPProxyResponse()
METHOD OpenProxy( cServer, nPort, cProxy, nProxyPort, cResp, cUserName, cPassWord, cUserAgent )
METHOD ReadHTTPProxyResponse( sResponse )
/* Methods to log data if needed */
METHOD InetRecv( SocketCon, cStr1, len)
@@ -156,8 +173,8 @@ CREATE CLASS tIPClient
METHOD InetRecvAll( SocketCon, cStr1, len )
METHOD InetCount( SocketCon )
METHOD InetSendAll( SocketCon, cData, nLen )
METHOD InetErrorCode(SocketCon)
METHOD InetErrorDesc(SocketCon)
METHOD InetErrorCode( SocketCon )
METHOD InetErrorDesc( SocketCon )
METHOD InetConnect( cServer, nPort, SocketCon )
METHOD Log()
@@ -166,11 +183,16 @@ ENDCLASS
METHOD New( oUrl, lTrace, oCredentials ) CLASS tIPClient
LOCAL oErr
LOCAL cProtoAccepted := "ftp,http,pop,smtp"
DEFAULT lTrace TO .F.
IF ! ::bInitSocks
hb_inetInit()
#if defined( HAVE_OPENSSL )
SSL_init()
RAND_seed( Time() + hb_username() + DToS( Date() ) + hb_DirBase() + NetName() )
#endif
::bInitSocks := .T.
ENDIF
@@ -178,7 +200,17 @@ METHOD New( oUrl, lTrace, oCredentials ) CLASS tIPClient
oUrl := tUrl():New( oUrl )
ENDIF
IF ! oURL:cProto $ "ftp,http,pop,smtp"
#if defined( HAVE_OPENSSL )
IF oURL:cProto == "ftps" .OR. ;
oURL:cProto == "https" .OR. ;
oURL:cProto == "pops" .OR. ;
oURL:cProto == "smtps"
::EnableTLS( .T. )
ENDIF
cProtoAccepted += "," + "ftps,https,pops,smtps"
#endif
IF ! oURL:cProto $ cProtoAccepted
oErr := ErrorNew()
oErr:Args := { Self, oURL:cProto }
oErr:CanDefault := .F.
@@ -223,10 +255,13 @@ METHOD Open( cUrl ) CLASS tIPClient
::SocketCon := hb_inetCreate()
hb_inetTimeout( ::SocketCon, ::nConnTimeout )
IF ISNUMBER( ::nConnTimeout )
hb_inetTimeout( ::SocketCon, ::nConnTimeout )
ENDIF
IF ! Empty( ::cProxyHost )
cResp := ""
IF ! ::OpenProxy( ::oUrl:cServer, nPort, ::cProxyHost, ::nProxyPort, @cResp, ::cProxyUser, ::cProxyPassword, ::nConnTimeout, "Mozilla/3.0 compatible" )
IF ! ::OpenProxy( ::oUrl:cServer, nPort, ::cProxyHost, ::nProxyPort, @cResp, ::cProxyUser, ::cProxyPassword, "Mozilla/3.0 compatible" )
RETURN .F.
ENDIF
ELSE
@@ -239,7 +274,34 @@ METHOD Open( cUrl ) CLASS tIPClient
::isOpen := .T.
RETURN .T.
METHOD OpenProxy( cServer, nPort, cProxy, nProxyPort, cResp, cUserName, cPassWord, nTimeOut, cUserAgent ) CLASS tIPClient
METHOD EnableTLS( lEnable ) CLASS tIPClient
LOCAL lSuccess
IF ::lTLS == lEnable
RETURN .T.
ENDIF
#if defined( HAVE_OPENSSL )
IF lEnable
::ssl_ctx := SSL_CTX_new()
::ssl := SSL_new( ::ssl_ctx )
::lTLS := .T.
lSuccess := .T.
ELSE
::lTLS := .F.
lSuccess := .T.
ENDIF
#else
IF lEnable
lSuccess := .F.
ELSE
lSuccess := .T.
ENDIF
#endif
RETURN lSuccess
METHOD OpenProxy( cServer, nPort, cProxy, nProxyPort, cResp, cUserName, cPassWord, cUserAgent ) CLASS tIPClient
LOCAL cRequest
LOCAL lRet := .F.
LOCAL tmp
@@ -257,7 +319,7 @@ METHOD OpenProxy( cServer, nPort, cProxy, nProxyPort, cResp, cUserName, cPassWor
cRequest += Chr( 13 ) + Chr( 10 )
::InetSendAll( ::SocketCon, cRequest )
cResp := ""
IF ::ReadHTTPProxyResponse( nTimeOut, @cResp )
IF ::ReadHTTPProxyResponse( @cResp )
tmp := At( " ", cResp )
IF tmp > 0 .AND. Val( SubStr( cResp, tmp + 1 ) ) == 200
lRet := .T.
@@ -273,17 +335,15 @@ METHOD OpenProxy( cServer, nPort, cProxy, nProxyPort, cResp, cUserName, cPassWor
RETURN lRet
METHOD ReadHTTPProxyResponse( dwTimeout, sResponse ) CLASS tIPClient
METHOD ReadHTTPProxyResponse( /* @ */ sResponse ) CLASS tIPClient
LOCAL bMoreDataToRead := .T.
LOCAL nLength, nData
LOCAL szResponse
HB_SYMBOL_UNUSED( dwTimeout )
DO WHILE bMoreDataToRead
szResponse := Space( 1 )
nData := hb_inetRecv( ::SocketCon, @szResponse, Len( szResponse ) )
nData := ::InetRecv( ::SocketCon, @szResponse, Len( szResponse ) )
IF nData == 0
RETURN .F.
ENDIF
@@ -305,6 +365,14 @@ METHOD Close() CLASS tIPClient
nRet := hb_inetClose( ::SocketCon )
#if defined( HAVE_OPENSSL )
IF ::lTLS
SSL_shutdown( ::ssl )
::ssl := NIL
::ssl_ctx := NIL
ENDIF
#endif
::SocketCon := NIL
::isOpen := .F.
ENDIF
@@ -346,11 +414,18 @@ METHOD Read( nLen ) CLASS tIPClient
// read an amount of data
cStr0 := Space( nLen )
// S.R. if len of file is less than RCV_BUF_SIZE hb_inetRecvAll return 0
// ::nLastRead := hb_inetRecvAll( ::SocketCon, @cStr0, nLen )
::InetRecvAll( ::SocketCon, @cStr0, nLen )
::nLastRead := ::InetCount( ::SocketCon )
IF ::lTLS
#if defined( HAVE_OPENSSL )
/* Getting around implementing the hack used in non-SSL branch for now.
IMO the proper fix would have been done to hb_inetRecvAll(). [vszakats] */
::nLastRead := ::InetRecvAll( ::SocketCon, @cStr0, nLen )
#endif
ELSE
// S.R. if len of file is less than RCV_BUF_SIZE hb_inetRecvAll return 0
// ::nLastRead := ::InetRecvAll( ::SocketCon, @cStr0, nLen )
::InetRecvAll( ::SocketCon, @cStr0, nLen )
::nLastRead := ::InetCount( ::SocketCon )
ENDIF
::nRead += ::nLastRead
IF ::nLastRead != nLen
@@ -459,7 +534,7 @@ METHOD WriteFromFile( cFile ) CLASS tIPClient
nLen := FRead( nFin, @cData, nBufSize )
ENDDO
// it may happen that the file has lenght 0
// it may happen that the file has length 0
IF nSent > 0
::Commit()
ENDIF
@@ -503,7 +578,19 @@ METHOD InetSendAll( SocketCon, cData, nLen ) CLASS tIPClient
nLen := Len( cData )
ENDIF
nRet := hb_inetSendAll( SocketCon, cData, nLen )
IF ::lTLS
#if defined( HAVE_OPENSSL )
#if defined( _SSL_DEBUG_TEMP )
? "SSL_WRITE()", cData
#endif
nRet := SSL_write( ::ssl, cData, nLen )
::nSSLError := iif( nRet < 0, nRet, 0 )
#else
nRet := 0
#endif
ELSE
nRet := hb_inetSendAll( SocketCon, cData, nLen )
ENDIF
IF ::lTrace
::Log( SocketCon, nlen, cData, nRet )
@@ -521,7 +608,21 @@ METHOD InetCount( SocketCon ) CLASS tIPClient
RETURN nRet
METHOD InetRecv( SocketCon, cStr1, len ) CLASS tIPClient
LOCAL nRet := hb_inetRecv( SocketCon, @cStr1, len )
LOCAL nRet
IF ::lTLS
#if defined( HAVE_OPENSSL )
#if defined( _SSL_DEBUG_TEMP )
? "SSL_READ()"
#endif
nRet := SSL_read( ::ssl, @cStr1, len )
::nSSLError := iif( nRet < 0, nRet, 0 )
#else
nRet := 0
#endif
ELSE
nRet := hb_inetRecv( SocketCon, @cStr1, len )
ENDIF
IF ::lTrace
::Log( SocketCon, "", len, iif( nRet >= 0, cStr1, nRet ) )
@@ -529,8 +630,26 @@ METHOD InetRecv( SocketCon, cStr1, len ) CLASS tIPClient
RETURN nRet
METHOD InetRecvLine( SocketCon, nLen, size ) CLASS tIPClient
LOCAL cRet := hb_inetRecvLine( SocketCon, @nLen, size )
METHOD InetRecvLine( SocketCon, nRet, size ) CLASS tIPClient
LOCAL cRet
IF ::lTLS
#if defined( HAVE_OPENSSL )
nRet := hb_SSL_read_line( ::ssl, @cRet, size, ::nConnTimeout )
#if defined( _SSL_DEBUG_TEMP )
? "HB_SSL_READ_LINE()", cRet
#endif
IF nRet == 0 .OR. Empty( cRet )
cRet := NIL
ENDIF
::nSSLError := iif( nRet < 0, nRet, 0 )
#else
cRet := ""
nRet := 0
#endif
ELSE
cRet := hb_inetRecvLine( SocketCon, @nRet, size )
ENDIF
IF ::lTrace
::Log( SocketCon, "", size, cRet )
@@ -538,17 +657,45 @@ METHOD InetRecvLine( SocketCon, nLen, size ) CLASS tIPClient
RETURN cRet
METHOD InetRecvAll( SocketCon, cStr1, len ) CLASS tIPClient
LOCAL nRet := hb_inetRecvAll( SocketCon, @cStr1, len )
METHOD InetRecvAll( SocketCon, cRet, size ) CLASS tIPClient
LOCAL nRet
IF ::lTLS
#if defined( HAVE_OPENSSL )
nRet := hb_SSL_read_all( ::ssl, @cRet, size, ::nConnTimeout )
#if defined( _SSL_DEBUG_TEMP )
? "HB_SSL_READ_ALL()", cRet
#endif
IF nRet == 0 .OR. Empty( cRet )
cRet := NIL
ENDIF
::nSSLError := iif( nRet < 0, nRet, 0 )
#else
cRet := ""
nRet := 0
#endif
ELSE
nRet := hb_inetRecvAll( SocketCon, @cRet, size )
ENDIF
IF ::lTrace
::Log( SocketCon, "", len, iif( nRet >= 0, cStr1, nRet ) )
::Log( SocketCon, "", size, iif( nRet >= 0, cRet, nRet ) )
ENDIF
RETURN nRet
METHOD InetErrorCode( SocketCon ) CLASS tIPClient
LOCAL nRet := hb_inetErrorCode( SocketCon )
LOCAL nRet
IF ::lTLS
#if defined( HAVE_OPENSSL )
nRet := iif( ::nSSLError == 0, 0, SSL_get_error( ::ssl, ::nSSLError ) )
#else
nRet := 0
#endif
ELSE
nRet := hb_inetErrorCode( SocketCon )
ENDIF
::nLastError := nRet
@@ -564,14 +711,22 @@ METHOD InetErrorDesc( SocketCon ) CLASS tIPClient
DEFAULT SocketCon TO ::SocketCon
IF ! Empty( SocketCon )
cMsg := hb_inetErrorDesc( SocketCon )
IF ::lTLS
#if defined( HAVE_OPENSSL )
IF ::nSSLError != 0
cMsg := ERR_error_string( SSL_get_error( ::ssl, ::nSSLError ) )
ENDIF
#endif
ELSE
cMsg := hb_inetErrorDesc( SocketCon )
ENDIF
ENDIF
RETURN cMsg
/* BROKEN, should test number of parameters and act accordingly, see doc\inet.txt */
METHOD InetConnect( cServer, nPort, SocketCon ) CLASS tIPClient
LOCAL tmp
hb_inetConnect( cServer, nPort, SocketCon )
IF ! Empty( ::nDefaultSndBuffSize )
@@ -582,6 +737,15 @@ METHOD InetConnect( cServer, nPort, SocketCon ) CLASS tIPClient
::InetRcvBufSize( SocketCon, ::nDefaultRcvBuffSize )
ENDIF
#if defined( HAVE_OPENSSL )
IF ::lTLS
SSL_set_mode( ::ssl, HB_SSL_MODE_AUTO_RETRY )
SSL_set_fd( ::ssl, hb_inetFD( SocketCon ) )
SSL_connect( ::ssl )
/* TODO: Add error handling */
ENDIF
#endif
IF ::lTrace
::Log( cServer, nPort, SocketCon )
ENDIF

View File

@@ -54,7 +54,7 @@
#translate ( <exp1> LIKE <exp2> ) => ( hb_regexLike( (<exp2>), (<exp1>) ) )
FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aFiles, cUser, cPass, cPopServer, nPriority, lRead, lTrace, lPopAuth, lNoAuth, nTimeOut, cReplyTo )
FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aFiles, cUser, cPass, cPopServer, nPriority, lRead, lTrace, lPopAuth, lNoAuth, nTimeOut, cReplyTo, lTLS, cSMTPPass )
/*
cServer -> Required. IP or domain name of the mail server
nPort -> Optional. Port used my email server
@@ -127,6 +127,12 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF
IF ! ISCHARACTER( cReplyTo )
cReplyTo := ""
ENDIF
IF ! ISLOGICAL( lTLS )
lTLS := .F.
ENDIF
IF ! ISCHARACTER( cSMTPPass )
cSMTPPass := cPass
ENDIF
cUser := StrTran( cUser, "@", "&at;" )
@@ -207,7 +213,7 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF
ENDIF
BEGIN SEQUENCE
oUrl := tUrl():New( "smtp://" + cUser + "@" + cServer + "/" + cTo )
oUrl := tUrl():New( iif( lTLS, "smtps://", "smtp://" ) + cUser + iif( Empty( cSMTPPass ), "", ":" + cSMTPPass ) + "@" + cServer + "/" + cTo )
RECOVER
lReturn := .F.
END SEQUENCE
@@ -278,19 +284,19 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF
ENDDO
IF lAuthLogin
IF ! oInMail:Auth( cUser, cPass )
IF ! oInMail:Auth( cUser, cSMTPPass )
lConnect := .F.
ELSE
lConnectPlain := .T.
lConnectPlain := .T.
ENDIF
ENDIF
IF lAuthPlain .AND. ! lConnect
IF !oInMail:AuthPlain( cUser, cPass )
IF ! oInMail:AuthPlain( cUser, cSMTPPass )
lConnect := .F.
ENDIF
ELSE
IF !lConnectPlain
IF ! lConnectPlain
oInmail:Getok()
lConnect := .F.
ENDIF
@@ -309,7 +315,7 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF
ENDIF
BEGIN SEQUENCE
oInmail := tIPClientsmtp():New( oUrl, lTrace )
oInmail := tIPClientSMTP():New( oUrl, lTrace )
RECOVER
lReturn := .F.
END SEQUENCE
@@ -332,14 +338,14 @@ FUNCTION hb_SendMail( cServer, nPort, cFrom, aTo, aCC, aBCC, cBody, cSubject, aF
oInMail:oUrl:cUserid := cFrom
oMail:hHeaders[ "To" ] := cTo
oMail:hHeaders[ "To" ] := cTo
oMail:hHeaders[ "Subject" ] := cSubject
FOR EACH aThisFile IN aFiles
IF ISCHARACTER( aThisFile )
cFile := aThisFile
cData := Memoread( cFile ) + Chr( 13 ) + Chr( 10 )
cData := MemoRead( cFile ) + Chr( 13 ) + Chr( 10 )
ELSEIF ISARRAY( aThisFile ) .AND. Len( aThisFile ) >= 2
cFile := aThisFile[ 1 ]
cData := aThisFile[ 2 ] + Chr( 13 ) + Chr( 10 )

View File

@@ -55,6 +55,9 @@
*/
#include "hbclass.ch"
#include "common.ch"
#include "tip.ch"
CREATE CLASS tIPClientSMTP FROM tIPClient
@@ -92,7 +95,7 @@ METHOD New( oUrl, lTrace, oCredentials ) CLASS tIPClientSMTP
::nConnTimeout := 5000
::nAccessMode := TIP_WO // a write only
IF ::ltrace
IF ::lTrace
IF ! hb_FileExists( "sendmail.log" )
::nHandle := FCreate( "sendmail.log" )
ELSE
@@ -106,7 +109,7 @@ METHOD New( oUrl, lTrace, oCredentials ) CLASS tIPClientSMTP
RETURN Self
METHOD Open( cUrl ) CLASS tIPClientSMTP
METHOD Open( cUrl, lTLS ) CLASS tIPClientSMTP
IF ! ::super:Open( cUrl )
RETURN .F.
@@ -114,11 +117,20 @@ METHOD Open( cUrl ) CLASS tIPClientSMTP
hb_inetTimeout( ::SocketCon, ::nConnTimeout )
DEFAULT lTLS TO .F.
IF lTLS
::InetSendall( ::SocketCon, "STARTTLS" + ::cCRLF )
IF ::GetOk()
::EnableTLS( .T. )
ENDIF
ENDIF
::InetSendall( ::SocketCon, "HELO " + iif( Empty( ::oUrl:cUserid ), "tipClientSMTP", ::oUrl:cUserid ) + ::cCRLF )
RETURN ::GetOk()
METHOD OpenSecure( cUrl ) CLASS tIPClientSMTP
METHOD OpenSecure( cUrl, lTLS ) CLASS tIPClientSMTP
IF ! ::super:Open( cUrl )
RETURN .F.
@@ -126,6 +138,15 @@ METHOD OpenSecure( cUrl ) CLASS tIPClientSMTP
hb_inetTimeout( ::SocketCon, ::nConnTimeout )
DEFAULT lTLS TO .F.
IF lTLS
::InetSendall( ::SocketCon, "STARTTLS" + ::cCRLF )
IF ::GetOk()
::EnableTLS( .T. )
ENDIF
ENDIF
::InetSendall( ::SocketCon, "EHLO " + iif( Empty( ::oUrl:cUserid ), "tipClientSMTP", ::oUrl:cUserid ) + ::cCRLF )
RETURN ::GetOk()
@@ -133,7 +154,7 @@ METHOD OpenSecure( cUrl ) CLASS tIPClientSMTP
METHOD GetOk() CLASS tIPClientSMTP
::cReply := ::InetRecvLine( ::SocketCon,, 512 )
IF ::InetErrorCode( ::SocketCon ) != 0 .OR. Left( ::cReply, 1 ) == "5"
IF ::InetErrorCode( ::SocketCon ) != 0 .OR. ! ISCHARACTER( ::cReply ) .OR. Left( ::cReply, 1 ) == "5"
RETURN .F.
ENDIF
@@ -141,7 +162,7 @@ METHOD GetOk() CLASS tIPClientSMTP
METHOD Close() CLASS tIPClientSMTP
hb_inetTimeOut( ::SocketCon, ::nConnTimeout )
IF ::ltrace
IF ::lTrace
FClose( ::nHandle )
ENDIF
::Quit()
@@ -250,7 +271,7 @@ METHOD SendMail( oTIpMail ) CLASS TIpClientSmtp
ENDIF
IF ! ::isAuth
::Auth( ::oUrl:cUserId, ::oUrl:cPassWord )
::Auth( ::oUrl:cUserId, ::oUrl:cPassword )
IF ! ::isAuth
RETURN .F.
ENDIF

View File

@@ -97,8 +97,6 @@ HB_FUNC( TIP_TIMESTAMP )
if( GetTimeZoneInformation( &tzInfo ) == TIME_ZONE_ID_INVALID )
tzInfo.Bias = 0;
else
tzInfo.Bias -= tzInfo.Bias;
if( ! pDate )
{