EnglishРусский  

   ..

   smtp.g

The project is closed! You can look at a new scripting language. It is available on GitHub.
Also, try our open source cross-platform automation software.

Ads

Installer and installation software
Commercial and Freeware installers.

source\lib\smtp\smtp.g
  1 /******************************************************************************
  2 *
  3 * Copyright (C) 2009, The Gentee Group. All rights reserved. 
  4 * This file is part of the Gentee open source project - http://www.gentee.com. 
  5 * 
  6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT"). 
  7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS 
  8 * ACCEPTANCE OF THE AGREEMENT.
  9 *
 10 * Author: Alexey Krivonogov ( gentee )
 11 *
 12 ******************************************************************************/
 13 
 14 include : $"..\socket\internet.g"
 15 include : $"..\endecode\base64.g"
 16 
 17 type smtp
 18 {
 19    str    username
 20    str    password
 21    socket sock        // Главный сокет
 22 	uint   notify      // Функция для уведомлений
 23 	inetnotify ni
 24 }
 25 
 26 define
 27 {
 28 /*	SMTP_OK      = 220
 29 	SMTP_GOODBYE = 221
 30    SMTP_HELLO   = 250
 31 */
 32    ERRSMTP_RESPONSE = 1
 33    ERRSMTP_QUIT 
 34    
 35    NFYSMTP_RESPONSE = $NFYFTP_RESPONSE
 36    NFYSMTP_SENDCMD = $NFYFTP_SENDCMD
 37 }
 38 /*
 39 type timetm {
 40         int tm_sec
 41         int tm_min
 42         int tm_hour
 43         int tm_mday
 44         int tm_mon
 45         int tm_year
 46         int tm_wday
 47         int tm_yday
 48         int tm_isdst
 49 }
 50 
 51 import "msvcrt.dll" <cdeclare> 
 52 {
 53    uint strftime( uint, uint, uint, timetm )
 54 }
 55 
 56 method str str.formatdate( datetime dt, str format )
 57 {
 58    timetm tm
 59    int   len
 60    
 61    this.clear()
 62    this.reserve( 64 )   
 63    tm.tm_sec = dt.second
 64    tm.tm_min = dt.minute
 65    tm.tm_hour = dt.hour
 66    tm.tm_mday = dt.day
 67    tm.tm_mon  = dt.month - 1
 68    tm.tm_year = dt.year - 1900
 69    tm.tm_wday = dt.dayofweek
 70 
 71    len = strftime( this.ptr(), 64, format.ptr(), tm )
 72    if len > 0 : this.setlen( len )          
 73    return this
 74 }
 75 */
 76 func str getdateformat_en( datetime systime, str format, str date )
 77 {
 78    uint locale
 79    //#define LANG_ENGLISH                     0x09
 80    //#define SUBLANG_ENGLISH_US               0x01  
 81    //MAKELCID(lgid, srtid) = (srtid) << 16 | lgid
 82    // SORT_DEFAULT 0
 83    locale = 0x09 | (0x01 << 10 )//MAKELCID(lgid, srtid)
 84    date.reserve( 64 )
 85    return date.setlen( GetDateFormat( locale, 0, 
 86             systime, format.ptr(), 
 87                                      date.ptr(), 64 ) - 1 )
 88 }
 89 
 90 method uint smtp.notify( uint code )
 91 {
 92    if !this.notify : return 1
 93       
 94    if !this.notify->func( code, this.ni )
 95    {
 96       ineterror = $ERRINET_USERBREAK
 97       return 0
 98    }
 99 	if code == $NFYINET_ERROR : return 0 
100    return 1
101 }
102 
103 method str smtp.lastresponse( str out )
104 {
105 	return out = this.ni.head
106 }
107 
108 method uint smtp.sendcmd( str cmd )
109 {
110 	this.ni.head = cmd
111 	if !this.ni.head.islast( 0xA ) : this.ni.head += "\l"
112 
113 	if !this.sock.send( this.ni.head ) : return this.notify( $NFYINET_ERROR )
114 	this.notify( $NFYSMTP_SENDCMD )
115 
116 	return 1	
117 }
118 
119 
120 method uint smtp.cmdresponse
121 {
122 	uint ret i
123 	buf  data
124 	arrstr  lines 
125 
126 	subfunc uint nodigit( ubyte ch )
127 	{
128 		return ch < '0' || ch > '9'
129 	}
130 	label again
131 	this.sock.recv( data )
132 	data += byte( 0 )
133    this.ni.head = data->str
134 
135 	if *data == 1 : return 0
136 
137 	this.ni.head.split( lines, 0xA, 0 )
138 	foreach cur, lines
139 	{
140 		if nodigit( cur[0] ) || nodigit( cur[1] ) || nodigit( cur[2] ) ||
141 			( cur[3] != ' ' && cur[3] != '-' )
142 		{
143 			ineterror = $ERRSMTP_RESPONSE
144 			break						
145 		} 
146 		ret = uint( cur )
147 	}
148 /*	if (lines[ *lines - 1 ])[ 3 ] != ' '
149 	{
150 		data.use-- 
151  		goto again
152 	}*/
153    if ret >= 400 || ineterror == $ERRSMTP_RESPONSE
154    {
155       if ( ret >= 400 ) : ineterror = ret
156       this.notify( $NFYINET_ERROR ) 
157       return 0
158    }
159 	this.notify( $NFYSMTP_RESPONSE )
160 	return ret	
161 }
162 
163 method uint smtp.command( str cmd )
164 {
165 	if !this.sendcmd( cmd ) : return 0
166 	return this.cmdresponse()	
167 }
168 
169 method uint smtp.close()
170 {
171    uint cmd ret = 1
172 
173 	if this.sock.socket
174 	{
175       ret = this.command( "QUIT" )
176 /*		cmd = this.command( "QUIT" )
177 	  	if cmd && cmd != $SMTP_GOODBYE
178 		{
179 			ineterror = $ERRSMTP_QUIT
180 	      this.notify( $NFYINET_ERROR )
181 			ret = 0
182 		}*/
183 	  	this.sock.close( )
184 	}
185    return ret
186 }
187 
188 method uint smtp.open( str host, uint port, str username, str password, uint notify )
189 {
190    uint rsp
191    
192    .username = username
193    .password = password
194    .notify = notify
195    
196    .sock.host = host
197    .sock.port = port
198 
199    .ni.url = host   
200    this.notify( $NFYINET_CONNECT )
201    if !.sock.connect() : goto error
202    if !.cmdresponse() : goto error
203    if *username
204    { 
205       if .command("EHLO \(host)")
206       {
207          buf bpsw
208          str spsw 
209          
210          bpsw = '\i 0 \( username ) \(password)'
211          spsw.tobase64( bpsw->str )
212          if !.command( "AUTH PLAIN \(spsw)" )
213          {
214             this.close()
215             return 0
216          } 
217          return 1
218       }
219    }
220    else : rsp = .command( "HELO \(host)")
221    if !rsp : goto error
222    return 1
223 
224 	label error
225    this.notify( $NFYINET_ERROR )
226    this.close( )
227    return 0
228 }
229 
230 method uint smtp.send( str from, str to, str subject, str body, str exthead )
231 {
232    datetime dt
233    str      date time
234    str      data
235    arrstr   toi
236    
237    subfunc str getemail( str in out )
238    {
239       uint left right
240       left = in.findch('<')
241       right = in.findch('>')
242       if right < *in : out.substr( in, left + 1, right - left - 1)
243       else : out = in
244       out.trimspace() 
245       return out
246    }
247    
248    dt.getsystime()
249    getdateformat_en( dt, "ddd, dd MMM yyyy", date )
250    gettimeformat ( dt, " HH:mm:ss", time )
251    date += " \(time) +0000"
252 //   date.formatdate( dt, "%a, %d %b %Y %H:%M:%S +0000" )
253 
254    to.split( toi, ',', $SPLIT_NOSYS )
255    foreach curto, toi
256    {
257       str efrom eto
258       
259       getemail( from, efrom )
260       getemail( curto, eto )
261       data = "MAIL FROM: <\(efrom)>
262 RCPT TO: <\(eto)>
263 DATA
264 From: \(from)
265 To: \(curto)
266 Subject: \(subject)
267 Date: \(date)
268 Mime-Version: 1.0
269 \( ?( *exthead, "\(exthead)\l", "" ))
270 \(body)
271 .
272 "
273       uint off sent remain = *data
274    
275       while remain
276  	   {   
277          sent = send( this.sock.socket, data.ptr() + off, min( 0x7FFF, remain ), 0 )
278 		   if	sent == $SOCKET_ERROR 
279 		   {
280 			   inet_seterror()
281 			   this.sock.close()
282 			   goto close
283 		   }
284 		   else
285 		   {
286    		   this.ni.param += sent
287 			   if !this.notify( $NFYINET_PUT )
288 			   {
289 				  this.sock.close()
290  				  goto close
291 			   }
292 		   }
293      	   remain -= sent
294          off += sent
295   	   }
296       if !.cmdresponse() : return 0
297    }
298    return 1
299    label close
300    this.notify( $NFYINET_ERROR )
301    return 0
302 }
303