=begin

= net/pop.rb

== このライブラリについて

メールを受信するためのプロトコル POP3 (Post Office Protocol version 3) を
を扱うライブラリです。POP3 の実装は [RFC1939]
((<URL:http://www.ietf.org/rfc/rfc1939.txt>)) に基いています。

== 使用例

=== メールの受信

以下のコードは、メールを受信してファイル 'inbox/1' 'inbox/2'... に
書きこみ、サーバ上からメールを消します。pop3.server.address は適宜
読みかえてください。

    require 'net/pop'

    pop = Net::POP3.new( 'pop3.server.address', 110 )
    pop.start( 'YourAccount', 'YourPassword' )          ###
    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' ) {|f|
            f.write m.pop
        }
        m.delete
        i += 1
      end
      puts "#{pop.mails.size} mails popped."
    end
    pop.finish                                           ###

POP サーバはネットワークのむこうに存在するので、なにか仕事をさせる
にはその前に開始手続きを、終わったら終了手続きを、行わなければいけ
ません。それを行うのが Net::POP3#start と #finish で、POP3 オブジェクト
はその二つのメソッドの間でだけ有効になります。

サーバ上のメールは POPMail オブジェクトとして表現されており、この
オブジェクトのメソッドを呼ぶことでメールを取ってきたり消したりする
ことができます。POP3#mails はこの POPMail オブジェクトの配列であり、
POP3#each_mail はさらに mails.each のショートカットです。

=== 短くする

上の例はあえて省略や短縮用メソッドを避けたためにかなり冗長です。
まず、ブロック付きの Net::POP3.start を使うことで POP3.new #start
#finish を併合できます。

    require 'net/pop'

    Net::POP3.start( 'pop3.server.address', 110 )
                     'YourAccount', 'YourPassword' )
	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' ) {|f|
                f.write m.pop
	    }
	    m.delete
	    i += 1
	  end
          puts "#{pop.mails.size} mails popped."
	end
    }

POP3#delete_all を使うとさらに #each_mail と m.delete を
併合できます。

    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.delete_all do |m|
	    File.open( 'inbox/' + i.to_s, 'w' ) {|f|
		f.write m.pop
	    }
	    i += 1
	  end
	end
    }

クラスメソッドの POP3.delete_all を使うとさらに短くなります。

    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

=== ファイルに直接書く

これまでの例では m.pop の部分でメールをひとつの文字列として
うけとっていましたが、たとえば 3MB くらいある巨大なメールの場合は
これではまずい場合があります。そのような場合は以下のように m.pop
に File オブジェクトを与える手が使えます。

    require 'net/pop'
    Net::POP3.delete_all( 'pop3.server.address', 110,
                          'YourAccount', 'YourPassword' ) do |m|
      File.open( 'inbox', 'w' ) {|f|
          m.pop f   ####
      }
    end

=== APOP

Net::POP3 クラスのかわりに Net::APOP クラスを使うと、認証時に APOP を
使うようになります。また動的にノーマル POP と APOP を選択するには、
以下のように Net::POP3.APOP() メソッドを使うのが便利です。

    require 'net/pop'

    # use APOP authentication if $isapop == true
    pop = Net::POP3.APOP($isapop).new( 'apop.server.address', 110 )
    pop.start( YourAccount', 'YourPassword' ) {|pop|
        # Rest code is same.
    }

この方法はクラス自体を変えるので、クラスメソッドの start や foreach、
delete_all、auth_only なども APOP とともに使えます。

== Net::POP3 class

=== クラスメソッド

: new( address, port = 110, apop = false )
    Net::POP3 オブジェクトを生成します。まだ接続はしません。
    apop が真のときは APOP 認証を行うオブジェクトを生成します。

: start( address, port = 110, account, password )
: start( address, port = 110, account, password ) {|pop| .... }
    address の port 番ポートに接続し、アカウント account パスワード
    password で POP ログインします。第二引数 port に nil を渡すと
    POP3 のデフォルトポート(110)を使います。

        Net::POP3.start( addr, port, account, password ) {|pop|
	    pop.each_mail do |m|
	      file.write m.pop
	      m.delete
	    end
        }

: APOP( is_apop )
    bool が真なら Net::APOP クラス、偽なら Net::POP3 クラスを返します。
    以下の例のように使ってください。

        # example 1
        pop = Net::POP3::APOP($isapop).new( addr, port )

        # example 2
        Net::POP3::APOP($isapop).start( addr, port ) {|pop|
            ....
        }

: foreach( address, port = 110, account, password ) {|mail| .... }
    POP セッションを開き、サーバ上のすべてのメールに対して繰り返します。
    以下と同じです。

        Net::POP3.start( address, port, account, password ) {|pop|
            pop.each_mail do |m|
	      yield m
	    end
        }

        # example
        Net::POP3.foreach( 'your.pop.server', 110,
                           'YourAccount', 'YourPassword' ) do |m|
          file.write m.pop
          m.delete if $DELETE
        end

: delete_all( address, port = 110, account, password )
: delete_all( address, port = 110, account, password ) {|mail| .... }
    POP セッションを開き、サーバ上のメールをすべて削除します。
    ブロックが与えられた時は削除する前にブロックにそのメールを
    渡します。以下と同じです。

        # example
        Net::POP3.delete_all( addr, nil, 'YourAccount', 'YourPassword' ) do |m|
          m.pop file
        end

: auth_only( address, port = 110, account, password )
    POP セッションを開き認証だけを行って接続を切ります。
    POP before SMTP 専用です。

        # example
        Net::POP3.auth_only( 'your.pop3.server',
                             nil,     # using default (110)
                             'YourAccount',
                             'YourPassword' )

=== メソッド

: start( account, password )
: start( account, password ) {|pop| .... }
    リモートホストとの接続を開始し、アカウントに account、
    パスワードに password を使って POP ログインします。

: active?
    POP3 セッションが開始されていたら真。

: address
    接続するアドレス

: port
    接続するポート番号

: open_timeout
: open_timeout=(n)
    接続時に待つ最大秒数。この秒数たってもコネクションが
    開かなければ例外 TimeoutError を発生します。

: read_timeout
: read_timeout=(n)
    読みこみ (read(1) 一回) でブロックしてよい最大秒数。
    この秒数たっても読みこめなければ例外 TimeoutError を発生します。

: finish
    POP3 セッションを終了します。セッション開始前にこのメソッドが
    呼ばれた場合は例外 IOError を発生します。

: mails
    Net::POPMail オブジェクトの配列をかえします。
    この配列はセッションを開始したときに自動的に更新されます。

: each_mail {|popmail| .... }
: each {|popmail| .... }
    pop3.mails.each と同じです。

: delete_all
: delete_all {|popmail| .... }
    サーバ上のメールを全て消去します。
    ブロックを与えられたときは消去する前にその POPMail オブジェクトを
    ブロックに渡します。

        # example
        n = 1
        pop.delete_all do |m|
          File.open("inbox/#{n}") {|f| f.write m.pop }
          n += 1
        end

: auth_only( account, password )
    POP セッションを開き認証だけを行って接続を切ります。
    POP before SMTP 専用です。
        # example
        pop = Net::POP3.new( 'your.pop3.server' )
        pop.auth_only 'YourAccount', 'YourPassword'

: reset
    セッションをリセットします。
    具体的には POPMail#delete で消したメールが全て復活します。
    (POP3 ではメール一個だけを復活する方法はありません)

== Net::APOP

このクラスでは新しいメソッドは導入していません。
認証方式が APOP に変わるだけです。

=== スーパークラス
Net::POP3

== Net::POPMail

POP サーバー上のメール一通を抽象的に表現するクラス。
メールの取得や消去といった操作をカプセル化します。

=== メソッド

: pop( dest = '' )
    メールを受信して dest に << メソッドを使って書きこみます。
    dest を返します。

        # example
        allmails = nil
        POP3.start( 'your.pop3.server', 110,
                    'YourAccount, 'YourPassword' ) {|pop|
            allmails = pop.mails.collect {|popmail| popmail.pop }
        }

: pop {|str| .... }
    メールの文字列を少しづつ読みこみ、順次ブロックに与えます。

        # example
        POP3.start( 'localhost', 110 ) {|pop3|
	    pop3.each_mail do |m|
	      m.pop do |str|
		# do anything
	      end
	    end
        }

: header
    ヘッダだけを受信して文字列で返します。

: top( lines )
    メールヘッダと lines 行ぶんの本文を取得し文字列で返します。

: delete
    サーバ上からメールを削除します。

: size
    メールのサイズ (単位はバイト) をかえします。

: deleted?
    メールがサーバ上で消去されているとき真。消去してしまったら
    POP3#reset を使う以外に復活する方法はありません。

=end
