summaryrefslogtreecommitdiff
path: root/lib/net
diff options
context:
space:
mode:
authoraamine <aamine@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2001-06-26 23:49:21 +0000
committeraamine <aamine@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2001-06-26 23:49:21 +0000
commitc664027a342785089cc09169ff167350e840baa9 (patch)
tree2b74c20ddbfd9371414294e4c34ea3ce1e5afe95 /lib/net
parent10e80b2402f7c0fd79df86767a11ba4e4b1bfa95 (diff)
aamine
* lib/net/pop.rb: new methods POP3.auth_only, POP3#auth_only * lib/net/http.rb: HTTP.Proxy returns self if ADDRESS is nil. * lib/net/protocol.rb: new method ProtocolError#response * lib/net/protocol.rb,smtp.rb,pop.rb,http.rb: add document. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1546 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/net')
-rw-r--r--lib/net/http.rb488
-rw-r--r--lib/net/pop.rb337
-rw-r--r--lib/net/protocol.rb94
-rw-r--r--lib/net/smtp.rb203
4 files changed, 740 insertions, 382 deletions
diff --git a/lib/net/http.rb b/lib/net/http.rb
index bbe98274f4..6a8fc5f862 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -1,125 +1,304 @@
=begin
-= net/http.rb version 1.2.0
+= net/http.rb version 1.2.1
- Copyright (C) 1999-2001 Yukihiro Matsumoto
+Copyright (c) 1999-2001 Yukihiro Matsumoto
- written & maintained by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
- This file is derived from "http-access.rb".
+written & maintained by Minero Aoki <aamine@loveruby.net>
+This file is derived from "http-access.rb".
- This program is free software. You can re-distribute and/or
- modify this program under the same terms as Ruby itself,
- GNU General Public License or Ruby License.
+This program is free software. You can re-distribute and/or
+modify this program under the same terms as Ruby itself,
+Ruby Distribute License or GNU General Public License.
- Japanese version of this document is in "net" full package.
- You can get it from RAA (Ruby Application Archive). RAA is:
- http://www.ruby-lang.org/en/raa.html
+NOTE: You can get Japanese version of this document from
+Ruby Documentation Project (RDP):
+((<URL:http://www.ruby-lang.org/~rubikitch/RDP.cgi>))
+== What is this module?
+
+This module provide your program the functions to access WWW
+documents via HTTP, Hyper Text Transfer Protocol version 1.1.
+For details of HTTP, refer [RFC2616]
+((<URL:http://www.ietf.org/rfc/rfc2616.txt>)).
+
+== Examples
+
+=== Getting Document From Server
+
+Be care to ',' (comma) putted after "response".
+This is required for feature compatibility.
+
+ require 'net/http'
+ Net::HTTP.start( 'some.www.server', 80 ) {|http|
+ response , = http.get('/index.html')
+ puts response.body
+ }
+
+(shorter version)
+
+ require 'net/http'
+ Net::HTTP.get_print 'some.www.server', '/index.html'
+
+=== Posting Form Data
+
+ require 'net/http'
+ Net::HTTP.start( 'some.www.server', 80 ) {|http|
+ response , = http.post( '/cgi-bin/any.rhtml',
+ 'querytype=subject&target=ruby' )
+ }
+
+=== Accessing via Proxy
+
+Net::HTTP.Proxy() creates http proxy class. It has same
+methods of Net::HTTP but its instances always connect to
+proxy, instead of given host.
+
+ require 'net/http'
+
+ $proxy_addr = 'your.proxy.addr'
+ $proxy_port = 8080
+ :
+ Net::HTTP::Proxy($proxy_addr, $proxy_port).start( 'some.www.server' ) {|http|
+ # always connect to your.proxy.addr:8080
+ :
+ }
+
+Since Net::HTTP.Proxy() returns Net::HTTP itself when $proxy_addr is nil,
+there's no need to change code if there's proxy or not.
+
+=== Redirect
+
+ require 'net/http'
+ Net::HTTP.version_1_1
+
+ host = 'www.ruby-lang.org'
+ begin
+ Net::HTTP.start( host, 80 ) {|http|
+ response , = http.get('/')
+ }
+ rescue Net::ProtoRetriableError => err
+ if m = %r<http:([^/]+)>.match( err.response['location'] ) then
+ host = m[1].strip
+ retry
+ end
+ end
+
+NOTE: This code is using ad-hoc way to extract host name, but in future
+URI class will be included in ruby standard library.
+
+=== Basic Authentication
+
+ require 'net/http'
+
+ Net::HTTP.start( 'auth.some.domain' ) {|http|
+ response , = http.get( '/need-auth.cgi',
+ 'Authentication' => ["#{account}:#{password}"].pack('m').strip )
+ print response.body
+ }
+
+In version 1.2 (Ruby 1.7 or later), you can write like this:
+
+ require 'net/http'
+
+ req = Net::HTTP::Get.new('/need-auth.cgi')
+ req.basic_auth 'account', 'password'
+ Net::HTTP.start( 'auth.some.domain' ) {|http|
+ response = http.request( req )
+ print response.body
+ }
+
+== Switching Net::HTTP versions
+
+You can use old Net::HTTP (in Ruby 1.6) features by calling
+HTTP.version_1_1. And calling Net::HTTP.version_1_2 allows
+you to use 1.2 features again.
+
+ # example
+ Net::HTTP.start {|http1| ...(http1 has 1.2 features)... }
+
+ Net::HTTP.version_1_1
+ Net::HTTP.start {|http2| ...(http2 has 1.1 features)... }
+
+ Net::HTTP.version_1_2
+ Net::HTTP.start {|http3| ...(http3 has 1.2 features)... }
+
+Yes, this is not thread-safe.
== class Net::HTTP
=== Class Methods
: new( address = 'localhost', port = 80, proxy_addr = nil, proxy_port = nil )
- creates a new Net::HTTP object.
- If proxy_addr is given, this method is equals to
- Net::HTTP::Proxy(proxy_addr,proxy_port).
+ creates a new Net::HTTP object.
+ If proxy_addr is given, this method is equals to
+ Net::HTTP::Proxy(proxy_addr,proxy_port).
: start( address = 'localhost', port = 80, proxy_addr = nil, proxy_port = nil )
: start( address = 'localhost', port = 80, proxy_addr = nil, proxy_port = nil ) {|http| .... }
- is equals to
+ is equals to
- Net::HTTP.new( address, port, proxy_addr, proxy_port ).start(&block)
+ Net::HTTP.new(address, port, proxy_addr, proxy_port).start(&block)
: get( address, path, port = 80 )
- gets entity body from path and returns it.
- return value is a String.
+ gets entity body from path and returns it.
+ return value is a String.
: get_print( address, path, port = 80 )
- gets entity body from path and print it.
- return value is an entity body (a String).
-
-: Proxy( address, port )
- creates a HTTP proxy class.
- Arguments are address/port of proxy host.
- You can replace HTTP class by this proxy class.
-
- # example
- proxy_http = HTTP::Proxy( 'proxy.foo.org', 8080 )
- :
- proxy_http.start( 'www.ruby-lang.org' ) do |http|
- # connecting proxy.foo.org:8080
- :
- end
+ gets entity body from path and print it.
+ return value is an entity body (a String).
+
+: Proxy( address, port = 80 )
+ creates a HTTP proxy class.
+ Arguments are address/port of proxy host.
+ You can replace HTTP class by this proxy class.
+
+ If ADDRESS is nil, this method returns self (Net::HTTP class).
+
+ # example
+ proxy_class = Net::HTTP::Proxy( 'proxy.foo.org', 8080 )
+ :
+ proxy_class.start( 'www.ruby-lang.org' ) do |http|
+ # connecting proxy.foo.org:8080
+ :
+ end
: proxy_class?
- If self is HTTP, false.
- If self is a class which was created by HTTP::Proxy(), true.
+ If self is HTTP, false.
+ If self is a class which was created by HTTP::Proxy(), true.
: port
- HTTP default port (80).
-
+ HTTP default port (80).
=== Instance Methods
: start
: start {|http| .... }
- creates a new Net::HTTP object and starts HTTP session.
+ creates a new Net::HTTP object and starts HTTP session.
+
+ When this method is called with block, gives a HTTP object to block
+ and close the HTTP session after block call finished.
+
+: active?
+ true if HTTP session is started.
+
+: address
+ the address to connect
+
+: port
+ the port number to connect
- When this method is called with block, gives HTTP object to block
- and close HTTP session after block call finished.
+: open_timeout
+: open_timeout=(n)
+ seconds to wait until connection is opened.
+ If HTTP object cannot open a conection in this seconds,
+ it raises TimeoutError exception.
+
+: read_timeout
+: read_timeout=(n)
+ seconds to wait until reading one block (by one read(1) call).
+ If HTTP object cannot open a conection in this seconds,
+ it raises TimeoutError exception.
+
+: finish
+ finishes HTTP session.
+ If HTTP session had not started, do nothing and return false.
: proxy?
- true if self is a HTTP proxy class
+ true if self is a HTTP proxy class
: proxy_address
- address of proxy host. If self is not a proxy, nil.
+ address of proxy host. If self is not a proxy, nil.
: proxy_port
- port number of proxy host. If self is not a proxy, nil.
+ port number of proxy host. If self is not a proxy, nil.
: get( path, header = nil, dest = '' )
: get( path, header = nil ) {|str| .... }
- gets data from "path" on connecting host.
- "header" must be a Hash like { 'Accept' => '*/*', ... }.
- Response body is written into "dest" by using "<<" method.
- This method returns Net::HTTPResponse object.
+ gets data from "path" on connecting host.
+ "header" must be a Hash like { 'Accept' => '*/*', ... }.
+ Response body is written into "dest" by using "<<" method.
+ This method returns Net::HTTPResponse object.
- # example
- response = http.get( '/index.html' )
+ If called with block, give a part String of entity body.
- If called with block, give a part String of entity body.
+ In version 1.1, this method might raises exception for also
+ 3xx (redirect). On the case you can get response object by
+ err.response.
-: head( path, header = nil )
- gets only header from "path" on connecting host.
- "header" is a Hash like { 'Accept' => '*/*', ... }.
- This method returns a Net::HTTPResponse object.
- You can http header from this object like:
+ In version 1.2, this method never raises exception.
- response['content-length'] #-> '2554'
- response['content-type'] #-> 'text/html'
- response['Content-Type'] #-> 'text/html'
- response['CoNtEnT-tYpe'] #-> 'text/html'
+ # version 1.1 (Ruby 1.6)
+ response, body = http.get( '/index.html' )
-: post( path, data, header = nil, dest = '' )
-: post( path, data, header = nil ) {|str| .... }
- posts "data" (must be String) to "path".
- If the body exists, also gets entity body.
- Response body is written into "dest" by using "<<" method.
- "header" must be a Hash like { 'Accept' => '*/*', ... }.
- This method returns Net::HTTPResponse object.
+ # version 1.2 (Ruby 1.7 or later)
+ response = http.get( '/index.html' )
- If called with block, gives a part of entity body string.
+ # compatible in both version
+ response , = http.get( '/index.html' )
+ response.body
+
+ # using block
+ File.open( 'save.txt', 'w' ) {|f|
+ http.get( '/~foo/', nil ) do |str|
+ f.write str
+ end
+ }
+ # some effect
+ File.open( 'save.txt', 'w' ) {|f|
+ http.get '/~foo/', nil, f
+ }
+: head( path, header = nil )
+ gets only header from "path" on connecting host.
+ "header" is a Hash like { 'Accept' => '*/*', ... }.
+ This method returns a Net::HTTPResponse object.
+ You can http header from this object like:
+
+ response = nil
+ Net::HTTP.start( 'some.www.server', 80 ) {|http|
+ response = http.head( '/index.html' )
+ }
+ response['content-length'] #-> '2554'
+ response['content-type'] #-> 'text/html'
+ response['Content-Type'] #-> 'text/html'
+ response['CoNtEnT-tYpe'] #-> 'text/html'
-: request( request, [src] )
-: request( request, [src] ) {|response| .... }
- sends REQUEST to (remote) http server. This method also writes
- string from SRC before it if REQUEST is a post/put request.
- (giving SRC for get/head request causes ArgumentError.)
+: post( path, data, header = nil, dest = '' )
+: post( path, data, header = nil ) {|str| .... }
+ posts "data" (must be String) to "path".
+ If the body exists, also gets entity body.
+ Response body is written into "dest" by using "<<" method.
+ "header" must be a Hash like { 'Accept' => '*/*', ... }.
+ This method returns Net::HTTPResponse object.
+
+ If called with block, gives a part of entity body string.
+
+ # version 1.1
+ response, body = http.post( '/index.html', 'querytype=subject&target=ruby' )
+ # version 1.2
+ response = http.post( '/index.html', 'querytype=subject&target=ruby' )
+ # compatible for both version
+ response , = http.post( '/index.html', 'querytype=subject&target=ruby' )
+
+ # using block
+ File.open( 'save.html', 'w' ) {|f|
+ http.post( '/index.html', 'querytype=subject&target=ruby' ) do |str|
+ f.write str
+ end
+ }
+ # same effect
+ File.open( 'save.html', 'w' ) {|f|
+ http.post '/index.html', 'querytype=subject&target=ruby', nil, f
+ }
- If called with block, gives a HTTP response object to the block.
+: request( request, [data] )
+: request( request, [src] ) {|response| .... }
+ sends REQUEST to (remote) http server. This method also writes
+ string from DATA string if REQUEST is a post/put request.
+ (giving DATA for get/head request causes ArgumentError.)
+ If called with block, gives a HTTPResponse object to the block.
== class Net::HTTP::Get, Head, Post
@@ -131,7 +310,7 @@ entity path. All arguments named "key" is case-insensitive.
: new
creats HTTP request object.
-=== Methods
+=== Instance Methods
: self[ key ]
returns the header field corresponding to the case-insensitive key.
@@ -140,13 +319,32 @@ entity path. All arguments named "key" is case-insensitive.
: self[ key ] = val
sets the header field corresponding to the case-insensitive key.
+: each {|name, val| .... }
+ iterates for each field name and value pair.
+
+: basic_auth( account, password )
+ set Authorization: header for basic auth.
+
+: range
+ returns a Range object which represents Range: header field.
+
+: range = r
+: set_range( i, len )
+ set Range: header from Range (arg r) or beginning index and
+ length from it (arg i&len).
+
+: content_length
+ returns a Integer object which represents Content-Length: header field.
+
+: content_range
+ returns a Range object which represents Content-Range: header field.
== class Net::HTTPResponse
HTTP response class. This class wraps response header and entity.
All arguments named KEY is case-insensitive.
-=== Methods
+=== Instance Methods
: self[ key ]
returns the header field corresponding to the case-insensitive key.
@@ -166,7 +364,7 @@ All arguments named KEY is case-insensitive.
iterates for each field name and value pair.
: canonical_each {|name,value| .... }
- iterates for each canonical field name and value pair.
+ iterates for each "canonical" field name and value pair.
: code
HTTP result code string. For example, '302'.
@@ -175,34 +373,18 @@ All arguments named KEY is case-insensitive.
HTTP result message. For example, 'Not Found'.
: read_body( dest = '' )
- gets response body and write it into DEST using "<<" method.
+ gets entity body and write it into DEST using "<<" method.
If this method is called twice or more, nothing will be done
and returns first DEST.
: read_body {|str| .... }
- gets response body little by little and pass it to block.
+ gets entity body little by little and pass it to block.
: body
- response body. If #read_body has been called, this method
- returns arg of #read_body, DEST. Else gets body as String
- and returns it.
+ response body. If #read_body has been called, this method returns
+ arg of #read_body DEST. Else gets body as String and returns it.
-== Switching Net::HTTP versions
-
-You can use Net::HTTP 1.1 features by calling HTTP.version_1_1 .
-And calling Net::HTTP.version_1_2 allows you to use 1.2 features
-again.
-
- # example
- HTTP.start {|http1| ...(http1 has 1.2 features)... }
-
- HTTP.version_1_1
- HTTP.start {|http2| ...(http2 has 1.1 features)... }
-
- HTTP.version_1_2
- HTTP.start {|http3| ...(http3 has 1.2 features)... }
-
=end
require 'net/protocol'
@@ -224,18 +406,13 @@ module Net
protocol_param :port, '80'
-
def initialize( addr = nil, port = nil )
super
- @proxy_address = nil
- @proxy_port = nil
-
@curr_http_version = HTTPVersion
@seems_1_0_server = false
end
-
private
def conn_command( sock )
@@ -255,7 +432,11 @@ module Net
class << self
def Proxy( p_addr, p_port = nil )
- ProxyMod.create_proxy_class( p_addr, p_port || self.port )
+ if p_addr then
+ ProxyMod.create_proxy_class( p_addr, p_port || self.port )
+ else
+ self
+ end
end
alias orig_new new
@@ -271,32 +452,34 @@ module Net
new( address, port, p_addr, p_port ).start( &block )
end
- def proxy_class?
- false
- end
+ @is_proxy_class = false
+ @proxy_addr = nil
+ @proxy_port = nil
- def proxy_address
- nil
+ def proxy_class?
+ @is_proxy_class
end
- def proxy_port
- nil
- end
+ attr_reader :proxy_address
+ attr_reader :proxy_port
end
def proxy?
- false
+ type.proxy?
end
def proxy_address
- nil
+ type.proxy_address
end
def proxy_port
- nil
+ type.proxy_port
end
+ alias proxyaddr proxy_address
+ alias proxyport proxy_port
+
def edit_path( path )
path
end
@@ -304,52 +487,22 @@ module Net
module ProxyMod
- class << self
-
- def create_proxy_class( p_addr, p_port )
- mod = self
- klass = Class.new( HTTP )
- klass.module_eval {
- include mod
- @proxy_address = p_addr
- @proxy_port = p_port
- }
- def klass.proxy_class?
- true
- end
-
- def klass.proxy_address
- @proxy_address
- end
-
- def klass.proxy_port
- @proxy_port
- end
-
- klass
- end
-
+ def self.create_proxy_class( p_addr, p_port )
+ mod = self
+ klass = Class.new( HTTP )
+ klass.module_eval {
+ include mod
+ @is_proxy = true
+ @proxy_address = p_addr
+ @proxy_port = p_port
+ }
+ klass
end
- def initialize( addr, port )
- super
- @proxy_address = type.proxy_address
- @proxy_port = type.proxy_port
- end
-
- attr_reader :proxy_address, :proxy_port
-
- alias proxyaddr proxy_address
- alias proxyport proxy_port
-
- def proxy?
- true
- end
-
private
def conn_socket( addr, port )
- super @proxy_address, @proxy_port
+ super proxy_address, proxy_port
end
def edit_path( path )
@@ -363,7 +516,11 @@ module Net
# for backward compatibility
#
- @@newimpl = true
+ if Version < '1.2.0' then ###noupdate
+ @@newimpl = false
+ else
+ @@newimpl = true
+ end
class << self
@@ -375,6 +532,10 @@ module Net
@@newimpl = false
end
+ def is_version_1_2?
+ @@newimpl
+ end
+
private
def setvar( obj )
@@ -662,15 +823,15 @@ module Net
d1 = m[1].to_i
d2 = m[2].to_i
- if m[1] and m[2] then arr.push (d1 .. d2)
- elsif m[1] then arr.push (d1 .. -1)
- elsif m[2] then arr.push (-d2 .. -1)
+ if m[1] and m[2] then arr.push d1..d2
+ elsif m[1] then arr.push d1..-1
+ elsif m[2] then arr.push -d2..-1
else
raise HTTPHeaderSyntaxError, 'range is not specified'
end
end
- return *arr
+ return arr
end
def range=( r, fin = nil )
@@ -906,7 +1067,10 @@ module Net
@buf.concat s
end
- alias << write
+ def <<( s )
+ @buf.concat s
+ self
+ end
def terminate
ret = @buf
@@ -1028,7 +1192,7 @@ module Net
end
def value
- SuccessCode === self or error! self
+ SuccessCode === self or error!
end
@@ -1134,4 +1298,8 @@ module Net
}
+
+ HTTPResponse = NetPrivate::HTTPResponse
+ HTTPResponseReceiver = NetPrivate::HTTPResponse
+
end # module Net
diff --git a/lib/net/pop.rb b/lib/net/pop.rb
index c61e09735d..fee68f25a0 100644
--- a/lib/net/pop.rb
+++ b/lib/net/pop.rb
@@ -1,25 +1,115 @@
=begin
-= net/pop.rb version 1.2.0
+= net/pop.rb version 1.2.1
- Copyright (C) 1999-2001 Yukihiro Matsumoto
+Copyright (c) 1999-2001 Yukihiro Matsumoto
- written & maintained by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
+written & maintained by Minero Aoki <aamine@loveruby.net>
- This program is free software. You can re-distribute and/or
- modify this program under the same terms as Ruby itself,
- GNU General Public License or Ruby License.
+This program is free software. You can re-distribute and/or
+modify this program under the same terms as Ruby itself,
+Ruby Distribute License or GNU General Public License.
- Japanese version of this document is in "net" full package.
- You can get it from RAA (Ruby Application Archive). RAA is:
- http://www.ruby-lang.org/en/raa.html
+NOTE: You can get Japanese version of this document from
+Ruby Documentation Project (RDP):
+((<URL:http://www.ruby-lang.org/~rubikitch/RDP.cgi>))
+== What is This Module?
-== Net::POP3
+This module provides your program the functions to retrieve
+mails via POP3, Post Office Protocol version 3. For details
+of POP3, refer [RFC1939] ((<URL:http://www.ietf.org/rfc/rfc1939.txt>)).
-=== Super Class
+== Examples
+
+=== Retrieving Mails
+
+This example retrieves mails from server and delete it (on server).
+Mails are written in file named 'inbox/1', 'inbox/2', ....
+Replace 'pop3.server.address' your POP3 server address.
+
+
+ require 'net/pop'
+
+ Net::POP3.start( 'pop3.server.address', 110,
+ 'YourAccount', 'YourPassword' ) {|pop|
+ if pop.mails.empty? then
+ puts 'no mail.'
+ else
+ i = 0
+ pop.each_mail do |m| # or "pop.mails.each ..."
+ File.open( 'inbox/' + i.to_s, 'w' ) do |f|
+ f.write m.pop
+ end
+ m.delete
+ i += 1
+ end
+ end
+ puts "#{pop.mails.size} mails popped."
+ }
+
+=== Shorter Version
+
+ require 'net/pop'
+ i = 0
+ Net::POP3.start( 'pop3.server.address', 110,
+ 'YourAccount', 'YourPassword' ) {|pop|
+ pop.delete_all do |m|
+ File.open( 'inbox/' + i.to_s, 'w' ) {|f|
+ f.write m.pop
+ }
+ i += 1
+ end
+ }
+
+And this is more shorter example.
+
+ require 'net/pop'
+ i = 0
+ Net::POP3.delete_all( 'pop3.server.address', 110,
+ 'YourAccount', 'YourPassword' ) do |m|
+ File.open( 'inbox/' + i.to_s, 'w' ) {|f|
+ f.write m.pop
+ }
+ i += 1
+ end
-Net::Protocol
+=== Writing to File directly
+
+All examples above get mail as one big string.
+This example does not create such one.
+
+ require 'net/pop'
+ Net::POP3.delete_all( 'pop3.server.address', 110,
+ 'YourAccount', 'YourPassword' ) do |m|
+ File.open( 'inbox', 'w' ) {|f|
+ m.pop f ####
+ }
+ end
+
+=== Using APOP
+
+net/pop also supports APOP authentication. There's two way to use APOP:
+(1) using APOP class instead of POP3
+(2) passing true for fifth argument of POP3.start
+
+ # (1)
+ require 'net/pop'
+ Net::APOP.start( 'apop.server.address', 110,
+ 'YourAccount', 'YourPassword' ) {|pop|
+ # Rest code is same.
+ }
+
+ # (2)
+ require 'net/pop'
+ Net::POP3.start( 'apop.server.address', 110,
+ 'YourAccount', 'YourPassword',
+ true ####
+ ) {|pop|
+ # Rest code is same.
+ }
+
+== Net::POP3 class
=== Class Methods
@@ -31,10 +121,9 @@ Net::Protocol
: start( address = 'localhost', port = 110, account, password ) {|pop| .... }
equals to Net::POP3.new( address, port ).start( account, password )
- # typical usage
- Net::POP3.start( addr, port, acnt, pass ) do |pop|
+ Net::POP3.start( addr, port, account, password ) do |pop|
pop.each_mail do |m|
- any_file.write m.pop
+ file.write m.pop
m.delete
end
end
@@ -49,9 +138,8 @@ Net::Protocol
end
end
- .
+ Typical usage:
- # typical usage
Net::POP3.foreach( addr, nil, acnt, pass ) do |m|
m.pop file
m.delete
@@ -59,120 +147,140 @@ Net::Protocol
: delete_all( address = 'localhost', port = 110, account, password )
: delete_all( address = 'localhost', port = 110, account, password ) {|mail| .... }
- starts POP3 session and delete all mails.
- If block is given, iterates for each POPMail object before delete.
+ starts POP3 session and delete all mails.
+ If block is given, iterates for each POPMail object before delete.
+
+ # example
+ Net::POP3.delete_all( addr, nil, 'YourAccount', 'YourPassword' ) do |m|
+ m.pop file
+ end
+
+: auth_only( address = 'localhost', port = 110, account, password )
+ (just for POP-before-SMTP)
+ opens POP3 session and does autholize and quit.
+ This method must not be called while POP3 session is opened.
+
+ # example
+ pop = Net::POP3.auth_only( 'your.pop3.server',
+ nil, # using default (110)
+ 'YourAccount',
+ 'YourPassword' )
- # typical usage
- Net::POP3.delete_all( addr, nil, acnt, pass ) do |m|
- m.pop file
- end
-
=== Instance Methods
: start( account, password )
: start( account, password ) {|pop| .... }
- starts POP3 session.
+ starts POP3 session.
+
+ When called with block, gives a POP3 object to block and
+ closes the session after block call finish.
+
+: active?
+ true if POP3 session is started.
+
+: address
+ the address to connect
+
+: port
+ the port number to connect
- When called with block, gives a POP3 object to block and
- closes the session after block call finish.
+: open_timeout
+: open_timeout=(n)
+ seconds to wait until connection is opened.
+ If POP3 object cannot open a conection in this seconds,
+ it raises TimeoutError exception.
+
+: read_timeout
+: read_timeout=(n)
+ seconds to wait until reading one block (by one read(1) call).
+ If POP3 object cannot open a conection in this seconds,
+ it raises TimeoutError exception.
+
+: finish
+ finishes POP3 session.
+ If POP3 session had not be started, does nothing and return false.
: mails
- an array of ((URL:#POPMail)).
- This array is renewed when session started.
+ an array of Net::POPMail objects.
+ This array is renewed when session started.
: each_mail {|popmail| .... }
: each {|popmail| .... }
- is equals to "pop3.mails.each"
+ is equals to "pop3.mails.each"
: delete_all
: delete_all {|popmail| .... }
- deletes all mails.
- If called with block, gives mails to the block before deleting.
-
- # example 1
- # pop and delete all mails
- n = 1
- pop.delete_all do |m|
- File.open("inbox/#{n}") {|f| f.write m.pop }
- n += 1
- end
+ deletes all mails on server.
+ If called with block, gives mails to the block before deleting.
+
+ # example
+ n = 1
+ pop.delete_all do |m|
+ File.open("inbox/#{n}") {|f| f.write m.pop }
+ n += 1
+ end
- # example 2
- # clear all mails on server
- Net::POP3.start( addr, port, acc, pass ) do |pop|
- pop.delete_all
- end
+: auth_only( account, password )
+ (just for POP-before-SMTP)
+ opens POP3 session and does autholize and quit.
+ This method must not be called while POP3 session is opened.
+ # example
+ pop = Net::POP3.new( 'your.pop3.server' )
+ pop.auth_only 'YourAccount', 'YourPassword'
: reset
reset the session. All "deleted mark" are removed.
-
== Net::APOP
This class defines no new methods.
Only difference from POP3 is using APOP authentification.
=== Super Class
-
Net::POP3
-
== Net::POPMail
A class of mail which exists on POP server.
-=== Super Class
-
-Object
-
-
-=== Methods
+=== Instance Methods
: pop( dest = '' )
- This method fetches a mail and write to 'dest' using '<<' method.
-
- # usage example
+ This method fetches a mail and write to 'dest' using '<<' method.
- mailarr = []
- POP3.start( 'localhost', 110 ) do |pop|
- pop.each_mail do |popm|
- mailarr.push popm.pop # all() returns 'dest' (this time, string)
- # or, you can also
- # popm.pop( $stdout ) # write mail to stdout
-
- # maybe you also want to delete mail after popping
- popm.delete
- end
- end
+ # example
+ allmails = nil
+ POP3.start( 'your.pop3.server', 110,
+ 'YourAccount, 'YourPassword' ) do |pop|
+ allmails = pop.mails.collect {|popmail| popmail.pop }
+ end
: pop {|str| .... }
- If pop() is called with block, it gives the block part strings of a mail.
+ gives the block part strings of a mail.
- # usage example
-
- POP3.start( 'localhost', 110 ) do |pop3|
- pop3.each_mail do |m|
- m.pop do |str|
- # do anything
- end
- end
- end
+ # example
+ POP3.start( 'localhost', 110 ) {|pop3|
+ pop3.each_mail do |m|
+ m.pop do |str|
+ # do anything
+ end
+ end
+ }
: header
- This method fetches only mail header.
+ This method fetches only mail header.
: top( lines )
- This method fetches mail header and 'lines' lines body.
+ This method fetches mail header and LINES lines of body.
: delete
-: delete!
- This method deletes mail.
+ deletes mail on server.
: size
- size of mail(bytes)
+ mail size (bytes)
: deleted?
- true if mail was deleted
+ true if mail was deleted
=end
@@ -205,7 +313,12 @@ module Net
pop.delete_all( &block )
end
end
-
+
+ def auth_only( address = nil, port = nil,
+ account = nil, password = nil )
+ new( address, port ).auth_only account, password
+ end
+
end
@@ -215,6 +328,18 @@ module Net
@apop = false
end
+ def auth_only( account = nil, password = nil )
+ begin
+ connect
+ @active = true
+ @command.auth address, port
+ @command.quit
+ ensure
+ @active = false
+ disconnect
+ end
+ end
+
attr :mails
def each_mail( &block )
@@ -225,6 +350,7 @@ module Net
alias each each_mail
def delete_all
+ io_check
@mails.each do |m|
yield m if block_given?
m.delete unless m.deleted?
@@ -247,23 +373,20 @@ module Net
(@apop ? type.apop_command_type : type.command_type).new(sock)
end
- def do_start( acnt, pwd )
- @command.auth( acnt, pwd )
+ def do_start( account, password )
+ @command.auth account, password
- @mails = []
+ mails = []
mtype = type.mail_type
@command.list.each_with_index do |size,idx|
- if size then
- @mails.push mtype.new( idx, size, @command )
- end
+ mails.push mtype.new(idx, size, @command) if size
end
- @mails.freeze
+ @mails = mails.freeze
end
def io_check
- if not @socket or @socket.closed? then
- raise IOError, 'pop session is not opened yet'
- end
+ (not @socket or @socket.closed?) and
+ raise IOError, 'pop session is not opened yet'
end
end
@@ -359,8 +482,9 @@ module Net
critical {
getok 'LIST'
@socket.read_pendlist do |line|
- num, siz = line.split( / +/o )
- arr[ num.to_i ] = siz.to_i
+ m = /\A(\d+)[ \t]+(\d+)/.match(line) or
+ raise BadResponse, "illegal response: #{line}"
+ arr[ m[1].to_i ] = m[2].to_i
end
}
arr
@@ -376,26 +500,26 @@ module Net
def top( num, lines = 0, dest = '' )
critical {
getok sprintf( 'TOP %d %d', num, lines )
- @socket.read_pendstr( dest )
+ @socket.read_pendstr dest
}
end
def retr( num, dest = '', &block )
critical {
- getok sprintf( 'RETR %d', num )
- @socket.read_pendstr( dest, &block )
+ getok sprintf('RETR %d', num)
+ @socket.read_pendstr dest, &block
}
end
def dele( num )
critical {
- getok sprintf( 'DELE %d', num )
+ getok sprintf('DELE %d', num)
}
end
def uidl( num )
critical {
- getok( sprintf 'UIDL %d', num ).msg.split(' ')[1]
+ getok( sprintf('UIDL %d', num) ).msg.split(' ')[1]
}
end
@@ -436,17 +560,16 @@ module Net
def initialize( sock )
rep = super( sock )
- m = /<.+>/.match( rep.msg )
- unless m then
- raise ProtoAuthError, "This is not APOP server: can't login"
- end
+ m = /<.+>/.match( rep.msg ) or
+ raise ProtoAuthError, "not APOP server: cannot login"
@stamp = m[0]
end
def auth( account, pass )
critical {
@socket.writeline sprintf( 'APOP %s %s',
- account, MD5.new(@stamp + pass).hexdigest )
+ account,
+ MD5.new(@stamp + pass).hexdigest )
check_reply_auth
}
end
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index a440ef0817..52c4926d43 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -1,62 +1,18 @@
=begin
-= net/protocol.rb version 1.2.0
+= net/protocol.rb version 1.2.1
- Copyright (C) 1999-2001 Yukihiro Matsumoto
+Copyright (c) 1999-2001 Yukihiro Matsumoto
- written & maintained by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
+written & maintained by Minero Aoki <aamine@loveruby.net>
- This program is free software. You can re-distribute and/or
- modify this program under the same terms as Ruby itself,
- GNU General Public License or Ruby License.
+This program is free software. You can re-distribute and/or
+modify this program under the same terms as Ruby itself,
+Ruby Distribute License or GNU General Public License.
- Japanese version of this document is in "net" full package.
- You can get it from RAA (Ruby Application Archive). RAA is:
- http://www.ruby-lang.org/en/raa.html
-
-
-== Net::Protocol
-
-the abstract class for some internet protocols
-
-=== Super Class
-
-Object
-
-=== Class Methods
-
-: new( address = 'localhost', port = nil )
- This method Creates a new protocol object.
-
-: start( address = 'localhost', port = nil, *protoargs )
-: start( address = 'localhost', port = nil, *protoargs ) {|proto| .... }
- This method creates a new Protocol object and opens a session.
- equals to Net::Protocol.new( address, port ).start( *protoargs )
-
-=== Methods
-
-: address
- the address of connecting server (FQDN).
-
-: port
- connecting port number
-
-: start( *args )
-: start( *args ) {|proto| .... }
- This method starts protocol. If protocol was already started,
- do nothing and returns false.
-
- '*args' are specified in subclasses.
-
- When is called with block, gives Protocol object to block and
- close session when block finished.
-
-: finish
- This method ends protocol. If you call this method before protocol starts,
- it only return false without doing anything.
-
-: active?
- true if session have been started
+NOTE: You can get Japanese version of this document from
+Ruby Documentation Project (RDP):
+((<URL:http://www.ruby-lang.org/~rubikitch/RDP.cgi>))
=end
@@ -76,8 +32,7 @@ module Net
class Protocol
- Version = '1.2.0'
-
+ Version = '1.2.1'
class << self
@@ -106,13 +61,17 @@ module Net
#
- # sub-class requirements
+ # --- Configuration Staffs for Sub Classes ---
+ #
+ # protocol_param port
+ # protocol_param command_type
+ # protocol_param socket_type (optional)
#
- # protocol_param command_type
- # protocol_param port
+ # private method do_start (optional)
+ # private method do_finish (optional)
#
- # private method do_start (optional)
- # private method do_finish (optional)
+ # private method on_connect (optional)
+ # private method on_disconnect (optional)
#
protocol_param :port, 'nil'
@@ -267,8 +226,8 @@ module Net
"#<#{type} #{code}>"
end
- def error!( data = nil )
- raise code_type.error_type.new( code + ' ' + Net.quote(msg), data )
+ def error!
+ raise code_type.error_type.new( code + ' ' + Net.quote(msg), self )
end
end
@@ -288,12 +247,13 @@ module Net
class ProtocolError
- def initialize( msg, data = nil )
+ def initialize( msg, resp )
super msg
- @data = data
+ @response = resp
end
- attr :data
+ attr :response
+ alias data response
def inspect
"#<#{type}>"
@@ -644,7 +604,7 @@ module Net
# private use only (can not handle 'break')
def read_pendlist
- D_off 'reading list...'
+ # D_off 'reading list...'
str = nil
i = 0
@@ -654,7 +614,7 @@ module Net
yield str
end
- D_on "read #{i} items"
+ # D_on "read #{i} items"
end
diff --git a/lib/net/smtp.rb b/lib/net/smtp.rb
index 3b1d100fb3..52402a46f6 100644
--- a/lib/net/smtp.rb
+++ b/lib/net/smtp.rb
@@ -1,86 +1,193 @@
=begin
-= net/smtp.rb version 1.2.0
+= net/smtp.rb version 1.2.1
- Copyright (C) 1999-2001 Yukihiro Matsumoto
+Copyright (c) 1999-2001 Yukihiro Matsumoto
- written & maintained by Minero Aoki <aamine@dp.u-netsurf.ne.jp>
+written & maintained by Minero Aoki <aamine@loveruby.net>
- This program is free software. You can re-distribute and/or
- modify this program under the same terms as Ruby itself,
- GNU General Public License or Ruby License.
+This program is free software. You can re-distribute and/or
+modify this program under the same terms as Ruby itself,
+Ruby Distribute License or GNU General Public License.
- Japanese version of this document is in "net" full package.
- You can get it from RAA (Ruby Application Archive). RAA is:
- http://www.ruby-lang.org/en/raa.html
+NOTE: You can get Japanese version of this document from
+Ruby Documentation Project (RDP):
+((<URL:http://www.ruby-lang.org/~rubikitch/RDP.cgi>))
+== What is This Module?
-== Net::SMTP
+This module provides your program the functions to send internet
+mail via SMTP, Simple Mail Transfer Protocol. For details of
+SMTP itself, refer [RFC2821] ((<URL:http://www.ietf.org/rfc/rfc2821.txt>)).
-=== Super Class
+== What This Module is NOT?
-Net::Protocol
+This module does NOT provide the functions to compose internet
+mail. You must create it by yourself. For details of internet mail
+format, see [RFC2822] ((<URL:http://www.ietf.org/rfc/rfc2822.txt>)).
+
+== Examples
+
+=== Sending Mail
+
+You must open connection to SMTP server before sending mails.
+First argument is the address of SMTP server, and second argument
+is port number. Using SMTP.start with block is the most simple way
+to do it. SMTP Connection is closed automatically after block is
+executed.
+
+ require 'net/smtp'
+ Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp|
+ # use smtp object only in this block
+ }
+
+Replace 'your.smtp.server' by your SMTP server. Normally
+your system manager or internet provider is supplying a server
+for you.
+
+Then you can send mail.
+
+ require 'net/smtp'
+
+ Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp|
+ smtp.send_mail <<EndOfMail, 'your@mail.address', 'to@some.domain'
+ From: Your Name <your@mail.address>
+ To: Dest Address <to@some.domain>
+ Subject: test mail
+ Date: Sat, 23 Jun 2001 16:26:43 +0900
+ Message-Id: <unique.message.id.string@some.domain>
+
+ This is test mail.
+ EndOfMail
+ }
+
+=== Sending Mails from Any Sources
+
+In an example above I sent mail from String (here document literal).
+SMTP#send_mail accepts any objects which has "each" method
+like File and Array.
+
+ require 'net/smtp'
+ Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp|
+ File.open( 'Mail/draft/1' ) {|f|
+ smtp.send_mail f, 'your@mail.address', 'to@some.domain'
+ }
+ }
+
+=== Giving "Hello" Domain
+
+If your machine does not have canonical host name, maybe you
+must designate the third argument of SMTP.start.
+
+ Net::SMTP.start( 'your.smtp.server', 25,
+ 'mail.from.domain' ) {|smtp|
+
+This argument gives MAILFROM domain, the domain name that
+you send mail from. SMTP server might judge if he (or she?)
+send or reject SMTP session by this data.
+
+== class Net::SMTP
=== Class Methods
: new( address = 'localhost', port = 25 )
creates a new Net::SMTP object.
-: start( address = 'localhost', port = 25, *protoargs )
-: start( address = 'localhost', port = 25, *protoargs ) {|smtp| .... }
- is equal to Net::SMTP.new( address, port ).start( *protoargs )
+: start( address = 'localhost', port = 25, helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil )
+: start( address = 'localhost', port = 25, helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) {|smtp| .... }
+ is equal to
+ Net::SMTP.new(address,port).start(helo_domain,account,password,authtype)
-=== Methods
+ # example
+ Net::SMTP.start( 'your.smtp.server' ) {
+ smtp.send_mail mail_string, 'from@mail.address', 'dest@mail.address'
+ }
-: start( helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil )
-: start( helo_domain = Socket.gethostname, account = nil, password = nil, authtype = nil ) {|smtp| .... }
+=== Instance Methods
+
+: start( helo_domain = <local host name>, account = nil, password = nil, authtype = nil )
+: start( helo_domain = <local host name>, account = nil, password = nil, authtype = nil ) {|smtp| .... }
opens TCP connection and starts SMTP session.
If protocol had been started, do nothing and return false.
+ HELO_DOMAIN is a domain that you'll dispatch mails from.
When this methods is called with block, give a SMTP object to block and
close session after block call finished.
- If account and password are given, is trying to get authentication
- by using AUTH command. "authtype" is :plain (symbol) or :cram_md5.
+ If both of account and password are given, is trying to get
+ authentication by using AUTH command. :plain or :cram_md5 is
+ allowed for AUTHTYPE.
-: send_mail( mailsrc, from_addr, *to_addrs )
-: sendmail( mailsrc, from_addr, *to_addrs )
- This method sends 'mailsrc' as mail. SMTP read strings
- from 'mailsrc' by calling 'each' iterator, and convert them
- into "\r\n" terminated string when write.
+: active?
+ true if SMTP session is started.
- from_addr must be String.
- to_addrs must be a String(s) or an Array of String.
+: address
+ the address to connect
- Exceptions which SMTP raises are:
- * Net::ProtoSyntaxError: syntax error (errno.500)
- * Net::ProtoFatalError: fatal error (errno.550)
- * Net::ProtoUnknownError: unknown error
- * Net::ProtoServerBusy: temporary error (errno.420/450)
+: port
+ the port number to connect
- # usage example
+: open_timeout
+: open_timeout=(n)
+ seconds to wait until connection is opened.
+ If SMTP object cannot open a conection in this seconds,
+ it raises TimeoutError exception.
- Net::SMTP.start( 'localhost', 25 ) do |smtp|
- smtp.send_mail mail_string, 'from-addr@foo.or.jp', 'to-addr@bar.or.jp'
- end
+: read_timeout
+: read_timeout=(n)
+ seconds to wait until reading one block (by one read(1) call).
+ If SMTP object cannot open a conection in this seconds,
+ it raises TimeoutError exception.
-: ready( from_addr, to_addrs ) {|adapter| .... }
- This method stands by the SMTP object for sending mail.
- "adapter" object accepts only "write" method.
-
- # usage example
+: finish
+ finishes SMTP session.
+ If SMTP session had not started, do nothing and return false.
- Net::SMTP.start( 'localhost', 25 ) do |smtp|
- smtp.ready( from, to ) do |adapter|
+: send_mail( mailsrc, from_addr, *to_addrs )
+ This method sends MAILSRC as mail. A SMTP object read strings
+ from MAILSRC by calling "each" iterator, with converting them
+ into CRLF ("\r\n") terminated string when write.
+
+ FROM_ADDR must be a String, representing source mail address.
+ TO_ADDRS must be Strings or an Array of Strings, representing
+ destination mail addresses.
+
+ # example
+ Net::SMTP.start( 'your.smtp.server' ) {|smtp|
+ smtp.send_mail mail_string,
+ 'from@mail.address',
+ 'dest@mail.address' 'dest2@mail.address'
+ }
+
+: ready( from_addr, *to_addrs ) {|adapter| .... }
+ This method stands by the SMTP object for sending mail and
+ give adapter object to the block. ADAPTER accepts only "write"
+ method.
+
+ FROM_ADDR must be a String, representing source mail address.
+ TO_ADDRS must be Strings or an Array of Strings, representing
+ destination mail addresses.
+
+ # example
+ Net::SMTP.start( 'your.smtp.server', 25 ) {|smtp|
+ smtp.ready( 'from@mail.addr', 'dest@mail.addr' ) do |adapter|
adapter.write str1
adapter.write str2
adapter.write str3
end
- end
+ }
-: finish
- finishes SMTP session.
- If SMTP session had not started, do nothing and return false.
+== Exceptions
+
+SMTP objects raise these exceptions:
+: Net::ProtoSyntaxError
+ syntax error (errno.500)
+: Net::ProtoFatalError
+ fatal error (errno.550)
+: Net::ProtoUnknownError
+ unknown error. (is probably bug)
+: Net::ProtoServerBusy
+ temporary error (errno.420/450)
=end
@@ -155,7 +262,7 @@ module Net
if user or secret then
(user and secret) or
- raise ArgumentError, "both of account and password are required"
+ raise ArgumentError, 'both of account and password are required'
mid = 'auth_' + (authtype || 'cram_md5').to_s
@command.respond_to? mid or