net-pop 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3ef035bbd20a58700e4815d4bf06f46a9691fc357a720bb74d7fc56f23347f85
4
+ data.tar.gz: 9acb213cdb2f86913441a16f214528748f7c84724772ad3ff35be8808ea32ce2
5
+ SHA512:
6
+ metadata.gz: fd1a187335df8a35903493beb209d872fb49ec59f65088d095209786a51493ee3f80619bd53e2d831329fa85afd70e9e3fb23847603dd3b755fa120001288def
7
+ data.tar.gz: db328d1b8b66fa497f2ed18b5831b4d08537c7f70ea4672ef62d701ab843bd05fb6e55056bd15e1c71aa74648d0d04f17a9b6f06a3af873d76a356d440c0d46e
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ Gemfile.lock
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ group :development do
4
+ gem "bundler"
5
+ gem "rake"
6
+ gem "test-unit"
7
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,66 @@
1
+ # Net::POP3
2
+
3
+ This library provides functionality for retrieving
4
+ email via POP3, the Post Office Protocol version 3. For details
5
+ of POP3, see [RFC1939] (http://www.ietf.org/rfc/rfc1939.txt).
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'net-pop'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install net-pop
22
+
23
+ ## Usage
24
+
25
+ This example retrieves messages from the server and deletes them
26
+ on the server.
27
+
28
+ Messages are written to files named 'inbox/1', 'inbox/2', ....
29
+ Replace 'pop.example.com' with your POP3 server address, and
30
+ 'YourAccount' and 'YourPassword' with the appropriate account
31
+ details.
32
+
33
+ ```ruby
34
+ require 'net/pop'
35
+
36
+ pop = Net::POP3.new('pop.example.com')
37
+ pop.start('YourAccount', 'YourPassword') # (1)
38
+ if pop.mails.empty?
39
+ puts 'No mail.'
40
+ else
41
+ i = 0
42
+ pop.each_mail do |m| # or "pop.mails.each ..." # (2)
43
+ File.open("inbox/#{i}", 'w') do |f|
44
+ f.write m.pop
45
+ end
46
+ m.delete
47
+ i += 1
48
+ end
49
+ puts "#{pop.mails.size} mails popped."
50
+ end
51
+ pop.finish # (3)
52
+ ```
53
+
54
+ 1. Call Net::POP3#start and start POP session.
55
+ 2. Access messages by using POP3#each_mail and/or POP3#mails.
56
+ 3. Close POP session by calling POP3#finish or use the block form of #start.
57
+
58
+ ## Development
59
+
60
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
61
+
62
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
63
+
64
+ ## Contributing
65
+
66
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/net-pop.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.ruby_opts << "-rhelper"
7
+ t.test_files = FileList['test/**/test_*.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "net/pop"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,1023 @@
1
+ # frozen_string_literal: true
2
+ # = net/pop.rb
3
+ #
4
+ # Copyright (c) 1999-2007 Yukihiro Matsumoto.
5
+ #
6
+ # Copyright (c) 1999-2007 Minero Aoki.
7
+ #
8
+ # Written & maintained by Minero Aoki <aamine@loveruby.net>.
9
+ #
10
+ # Documented by William Webber and Minero Aoki.
11
+ #
12
+ # This program is free software. You can re-distribute and/or
13
+ # modify this program under the same terms as Ruby itself,
14
+ # Ruby Distribute License.
15
+ #
16
+ # NOTE: You can find Japanese version of this document at:
17
+ # http://docs.ruby-lang.org/ja/latest/library/net=2fpop.html
18
+ #
19
+ # $Id$
20
+ #
21
+ # See Net::POP3 for documentation.
22
+ #
23
+
24
+ require 'net/protocol'
25
+ require 'digest/md5'
26
+ require 'timeout'
27
+
28
+ begin
29
+ require "openssl"
30
+ rescue LoadError
31
+ end
32
+
33
+ module Net
34
+
35
+ # Non-authentication POP3 protocol error
36
+ # (reply code "-ERR", except authentication).
37
+ class POPError < ProtocolError; end
38
+
39
+ # POP3 authentication error.
40
+ class POPAuthenticationError < ProtoAuthError; end
41
+
42
+ # Unexpected response from the server.
43
+ class POPBadResponse < POPError; end
44
+
45
+ #
46
+ # == What is This Library?
47
+ #
48
+ # This library provides functionality for retrieving
49
+ # email via POP3, the Post Office Protocol version 3. For details
50
+ # of POP3, see [RFC1939] (http://www.ietf.org/rfc/rfc1939.txt).
51
+ #
52
+ # == Examples
53
+ #
54
+ # === Retrieving Messages
55
+ #
56
+ # This example retrieves messages from the server and deletes them
57
+ # on the server.
58
+ #
59
+ # Messages are written to files named 'inbox/1', 'inbox/2', ....
60
+ # Replace 'pop.example.com' with your POP3 server address, and
61
+ # 'YourAccount' and 'YourPassword' with the appropriate account
62
+ # details.
63
+ #
64
+ # require 'net/pop'
65
+ #
66
+ # pop = Net::POP3.new('pop.example.com')
67
+ # pop.start('YourAccount', 'YourPassword') # (1)
68
+ # if pop.mails.empty?
69
+ # puts 'No mail.'
70
+ # else
71
+ # i = 0
72
+ # pop.each_mail do |m| # or "pop.mails.each ..." # (2)
73
+ # File.open("inbox/#{i}", 'w') do |f|
74
+ # f.write m.pop
75
+ # end
76
+ # m.delete
77
+ # i += 1
78
+ # end
79
+ # puts "#{pop.mails.size} mails popped."
80
+ # end
81
+ # pop.finish # (3)
82
+ #
83
+ # 1. Call Net::POP3#start and start POP session.
84
+ # 2. Access messages by using POP3#each_mail and/or POP3#mails.
85
+ # 3. Close POP session by calling POP3#finish or use the block form of #start.
86
+ #
87
+ # === Shortened Code
88
+ #
89
+ # The example above is very verbose. You can shorten the code by using
90
+ # some utility methods. First, the block form of Net::POP3.start can
91
+ # be used instead of POP3.new, POP3#start and POP3#finish.
92
+ #
93
+ # require 'net/pop'
94
+ #
95
+ # Net::POP3.start('pop.example.com', 110,
96
+ # 'YourAccount', 'YourPassword') do |pop|
97
+ # if pop.mails.empty?
98
+ # puts 'No mail.'
99
+ # else
100
+ # i = 0
101
+ # pop.each_mail do |m| # or "pop.mails.each ..."
102
+ # File.open("inbox/#{i}", 'w') do |f|
103
+ # f.write m.pop
104
+ # end
105
+ # m.delete
106
+ # i += 1
107
+ # end
108
+ # puts "#{pop.mails.size} mails popped."
109
+ # end
110
+ # end
111
+ #
112
+ # POP3#delete_all is an alternative for #each_mail and #delete.
113
+ #
114
+ # require 'net/pop'
115
+ #
116
+ # Net::POP3.start('pop.example.com', 110,
117
+ # 'YourAccount', 'YourPassword') do |pop|
118
+ # if pop.mails.empty?
119
+ # puts 'No mail.'
120
+ # else
121
+ # i = 1
122
+ # pop.delete_all do |m|
123
+ # File.open("inbox/#{i}", 'w') do |f|
124
+ # f.write m.pop
125
+ # end
126
+ # i += 1
127
+ # end
128
+ # end
129
+ # end
130
+ #
131
+ # And here is an even shorter example.
132
+ #
133
+ # require 'net/pop'
134
+ #
135
+ # i = 0
136
+ # Net::POP3.delete_all('pop.example.com', 110,
137
+ # 'YourAccount', 'YourPassword') do |m|
138
+ # File.open("inbox/#{i}", 'w') do |f|
139
+ # f.write m.pop
140
+ # end
141
+ # i += 1
142
+ # end
143
+ #
144
+ # === Memory Space Issues
145
+ #
146
+ # All the examples above get each message as one big string.
147
+ # This example avoids this.
148
+ #
149
+ # require 'net/pop'
150
+ #
151
+ # i = 1
152
+ # Net::POP3.delete_all('pop.example.com', 110,
153
+ # 'YourAccount', 'YourPassword') do |m|
154
+ # File.open("inbox/#{i}", 'w') do |f|
155
+ # m.pop do |chunk| # get a message little by little.
156
+ # f.write chunk
157
+ # end
158
+ # i += 1
159
+ # end
160
+ # end
161
+ #
162
+ # === Using APOP
163
+ #
164
+ # The net/pop library supports APOP authentication.
165
+ # To use APOP, use the Net::APOP class instead of the Net::POP3 class.
166
+ # You can use the utility method, Net::POP3.APOP(). For example:
167
+ #
168
+ # require 'net/pop'
169
+ #
170
+ # # Use APOP authentication if $isapop == true
171
+ # pop = Net::POP3.APOP($isapop).new('apop.example.com', 110)
172
+ # pop.start('YourAccount', 'YourPassword') do |pop|
173
+ # # Rest of the code is the same.
174
+ # end
175
+ #
176
+ # === Fetch Only Selected Mail Using 'UIDL' POP Command
177
+ #
178
+ # If your POP server provides UIDL functionality,
179
+ # you can grab only selected mails from the POP server.
180
+ # e.g.
181
+ #
182
+ # def need_pop?( id )
183
+ # # determine if we need pop this mail...
184
+ # end
185
+ #
186
+ # Net::POP3.start('pop.example.com', 110,
187
+ # 'Your account', 'Your password') do |pop|
188
+ # pop.mails.select { |m| need_pop?(m.unique_id) }.each do |m|
189
+ # do_something(m.pop)
190
+ # end
191
+ # end
192
+ #
193
+ # The POPMail#unique_id() method returns the unique-id of the message as a
194
+ # String. Normally the unique-id is a hash of the message.
195
+ #
196
+ class POP3 < Protocol
197
+
198
+ # svn revision of this library
199
+ Revision = %q$Revision$.split[1]
200
+
201
+ #
202
+ # Class Parameters
203
+ #
204
+
205
+ # returns the port for POP3
206
+ def POP3.default_port
207
+ default_pop3_port()
208
+ end
209
+
210
+ # The default port for POP3 connections, port 110
211
+ def POP3.default_pop3_port
212
+ 110
213
+ end
214
+
215
+ # The default port for POP3S connections, port 995
216
+ def POP3.default_pop3s_port
217
+ 995
218
+ end
219
+
220
+ def POP3.socket_type #:nodoc: obsolete
221
+ Net::InternetMessageIO
222
+ end
223
+
224
+ #
225
+ # Utilities
226
+ #
227
+
228
+ # Returns the APOP class if +isapop+ is true; otherwise, returns
229
+ # the POP class. For example:
230
+ #
231
+ # # Example 1
232
+ # pop = Net::POP3::APOP($is_apop).new(addr, port)
233
+ #
234
+ # # Example 2
235
+ # Net::POP3::APOP($is_apop).start(addr, port) do |pop|
236
+ # ....
237
+ # end
238
+ #
239
+ def POP3.APOP(isapop)
240
+ isapop ? APOP : POP3
241
+ end
242
+
243
+ # Starts a POP3 session and iterates over each POPMail object,
244
+ # yielding it to the +block+.
245
+ # This method is equivalent to:
246
+ #
247
+ # Net::POP3.start(address, port, account, password) do |pop|
248
+ # pop.each_mail do |m|
249
+ # yield m
250
+ # end
251
+ # end
252
+ #
253
+ # This method raises a POPAuthenticationError if authentication fails.
254
+ #
255
+ # === Example
256
+ #
257
+ # Net::POP3.foreach('pop.example.com', 110,
258
+ # 'YourAccount', 'YourPassword') do |m|
259
+ # file.write m.pop
260
+ # m.delete if $DELETE
261
+ # end
262
+ #
263
+ def POP3.foreach(address, port = nil,
264
+ account = nil, password = nil,
265
+ isapop = false, &block) # :yields: message
266
+ start(address, port, account, password, isapop) {|pop|
267
+ pop.each_mail(&block)
268
+ }
269
+ end
270
+
271
+ # Starts a POP3 session and deletes all messages on the server.
272
+ # If a block is given, each POPMail object is yielded to it before
273
+ # being deleted.
274
+ #
275
+ # This method raises a POPAuthenticationError if authentication fails.
276
+ #
277
+ # === Example
278
+ #
279
+ # Net::POP3.delete_all('pop.example.com', 110,
280
+ # 'YourAccount', 'YourPassword') do |m|
281
+ # file.write m.pop
282
+ # end
283
+ #
284
+ def POP3.delete_all(address, port = nil,
285
+ account = nil, password = nil,
286
+ isapop = false, &block)
287
+ start(address, port, account, password, isapop) {|pop|
288
+ pop.delete_all(&block)
289
+ }
290
+ end
291
+
292
+ # Opens a POP3 session, attempts authentication, and quits.
293
+ #
294
+ # This method raises POPAuthenticationError if authentication fails.
295
+ #
296
+ # === Example: normal POP3
297
+ #
298
+ # Net::POP3.auth_only('pop.example.com', 110,
299
+ # 'YourAccount', 'YourPassword')
300
+ #
301
+ # === Example: APOP
302
+ #
303
+ # Net::POP3.auth_only('pop.example.com', 110,
304
+ # 'YourAccount', 'YourPassword', true)
305
+ #
306
+ def POP3.auth_only(address, port = nil,
307
+ account = nil, password = nil,
308
+ isapop = false)
309
+ new(address, port, isapop).auth_only account, password
310
+ end
311
+
312
+ # Starts a pop3 session, attempts authentication, and quits.
313
+ # This method must not be called while POP3 session is opened.
314
+ # This method raises POPAuthenticationError if authentication fails.
315
+ def auth_only(account, password)
316
+ raise IOError, 'opening previously opened POP session' if started?
317
+ start(account, password) {
318
+ ;
319
+ }
320
+ end
321
+
322
+ #
323
+ # SSL
324
+ #
325
+
326
+ @ssl_params = nil
327
+
328
+ # :call-seq:
329
+ # Net::POP.enable_ssl(params = {})
330
+ #
331
+ # Enable SSL for all new instances.
332
+ # +params+ is passed to OpenSSL::SSLContext#set_params.
333
+ def POP3.enable_ssl(*args)
334
+ @ssl_params = create_ssl_params(*args)
335
+ end
336
+
337
+ # Constructs proper parameters from arguments
338
+ def POP3.create_ssl_params(verify_or_params = {}, certs = nil)
339
+ begin
340
+ params = verify_or_params.to_hash
341
+ rescue NoMethodError
342
+ params = {}
343
+ params[:verify_mode] = verify_or_params
344
+ if certs
345
+ if File.file?(certs)
346
+ params[:ca_file] = certs
347
+ elsif File.directory?(certs)
348
+ params[:ca_path] = certs
349
+ end
350
+ end
351
+ end
352
+ return params
353
+ end
354
+
355
+ # Disable SSL for all new instances.
356
+ def POP3.disable_ssl
357
+ @ssl_params = nil
358
+ end
359
+
360
+ # returns the SSL Parameters
361
+ #
362
+ # see also POP3.enable_ssl
363
+ def POP3.ssl_params
364
+ return @ssl_params
365
+ end
366
+
367
+ # returns +true+ if POP3.ssl_params is set
368
+ def POP3.use_ssl?
369
+ return !@ssl_params.nil?
370
+ end
371
+
372
+ # returns whether verify_mode is enable from POP3.ssl_params
373
+ def POP3.verify
374
+ return @ssl_params[:verify_mode]
375
+ end
376
+
377
+ # returns the :ca_file or :ca_path from POP3.ssl_params
378
+ def POP3.certs
379
+ return @ssl_params[:ca_file] || @ssl_params[:ca_path]
380
+ end
381
+
382
+ #
383
+ # Session management
384
+ #
385
+
386
+ # Creates a new POP3 object and open the connection. Equivalent to
387
+ #
388
+ # Net::POP3.new(address, port, isapop).start(account, password)
389
+ #
390
+ # If +block+ is provided, yields the newly-opened POP3 object to it,
391
+ # and automatically closes it at the end of the session.
392
+ #
393
+ # === Example
394
+ #
395
+ # Net::POP3.start(addr, port, account, password) do |pop|
396
+ # pop.each_mail do |m|
397
+ # file.write m.pop
398
+ # m.delete
399
+ # end
400
+ # end
401
+ #
402
+ def POP3.start(address, port = nil,
403
+ account = nil, password = nil,
404
+ isapop = false, &block) # :yield: pop
405
+ new(address, port, isapop).start(account, password, &block)
406
+ end
407
+
408
+ # Creates a new POP3 object.
409
+ #
410
+ # +address+ is the hostname or ip address of your POP3 server.
411
+ #
412
+ # The optional +port+ is the port to connect to.
413
+ #
414
+ # The optional +isapop+ specifies whether this connection is going
415
+ # to use APOP authentication; it defaults to +false+.
416
+ #
417
+ # This method does *not* open the TCP connection.
418
+ def initialize(addr, port = nil, isapop = false)
419
+ @address = addr
420
+ @ssl_params = POP3.ssl_params
421
+ @port = port
422
+ @apop = isapop
423
+
424
+ @command = nil
425
+ @socket = nil
426
+ @started = false
427
+ @open_timeout = 30
428
+ @read_timeout = 60
429
+ @debug_output = nil
430
+
431
+ @mails = nil
432
+ @n_mails = nil
433
+ @n_bytes = nil
434
+ end
435
+
436
+ # Does this instance use APOP authentication?
437
+ def apop?
438
+ @apop
439
+ end
440
+
441
+ # does this instance use SSL?
442
+ def use_ssl?
443
+ return !@ssl_params.nil?
444
+ end
445
+
446
+ # :call-seq:
447
+ # Net::POP#enable_ssl(params = {})
448
+ #
449
+ # Enables SSL for this instance. Must be called before the connection is
450
+ # established to have any effect.
451
+ # +params[:port]+ is port to establish the SSL connection on; Defaults to 995.
452
+ # +params+ (except :port) is passed to OpenSSL::SSLContext#set_params.
453
+ def enable_ssl(verify_or_params = {}, certs = nil, port = nil)
454
+ begin
455
+ @ssl_params = verify_or_params.to_hash.dup
456
+ @port = @ssl_params.delete(:port) || @port
457
+ rescue NoMethodError
458
+ @ssl_params = POP3.create_ssl_params(verify_or_params, certs)
459
+ @port = port || @port
460
+ end
461
+ end
462
+
463
+ # Disable SSL for all new instances.
464
+ def disable_ssl
465
+ @ssl_params = nil
466
+ end
467
+
468
+ # Provide human-readable stringification of class state.
469
+ def inspect
470
+ +"#<#{self.class} #{@address}:#{@port} open=#{@started}>"
471
+ end
472
+
473
+ # *WARNING*: This method causes a serious security hole.
474
+ # Use this method only for debugging.
475
+ #
476
+ # Set an output stream for debugging.
477
+ #
478
+ # === Example
479
+ #
480
+ # pop = Net::POP.new(addr, port)
481
+ # pop.set_debug_output $stderr
482
+ # pop.start(account, passwd) do |pop|
483
+ # ....
484
+ # end
485
+ #
486
+ def set_debug_output(arg)
487
+ @debug_output = arg
488
+ end
489
+
490
+ # The address to connect to.
491
+ attr_reader :address
492
+
493
+ # The port number to connect to.
494
+ def port
495
+ return @port || (use_ssl? ? POP3.default_pop3s_port : POP3.default_pop3_port)
496
+ end
497
+
498
+ # Seconds to wait until a connection is opened.
499
+ # If the POP3 object cannot open a connection within this time,
500
+ # it raises a Net::OpenTimeout exception. The default value is 30 seconds.
501
+ attr_accessor :open_timeout
502
+
503
+ # Seconds to wait until reading one block (by one read(1) call).
504
+ # If the POP3 object cannot complete a read() within this time,
505
+ # it raises a Net::ReadTimeout exception. The default value is 60 seconds.
506
+ attr_reader :read_timeout
507
+
508
+ # Set the read timeout.
509
+ def read_timeout=(sec)
510
+ @command.socket.read_timeout = sec if @command
511
+ @read_timeout = sec
512
+ end
513
+
514
+ # +true+ if the POP3 session has started.
515
+ def started?
516
+ @started
517
+ end
518
+
519
+ alias active? started? #:nodoc: obsolete
520
+
521
+ # Starts a POP3 session.
522
+ #
523
+ # When called with block, gives a POP3 object to the block and
524
+ # closes the session after block call finishes.
525
+ #
526
+ # This method raises a POPAuthenticationError if authentication fails.
527
+ def start(account, password) # :yield: pop
528
+ raise IOError, 'POP session already started' if @started
529
+ if block_given?
530
+ begin
531
+ do_start account, password
532
+ return yield(self)
533
+ ensure
534
+ do_finish
535
+ end
536
+ else
537
+ do_start account, password
538
+ return self
539
+ end
540
+ end
541
+
542
+ # internal method for Net::POP3.start
543
+ def do_start(account, password) # :nodoc:
544
+ s = Timeout.timeout(@open_timeout, Net::OpenTimeout) do
545
+ TCPSocket.open(@address, port)
546
+ end
547
+ if use_ssl?
548
+ raise 'openssl library not installed' unless defined?(OpenSSL)
549
+ context = OpenSSL::SSL::SSLContext.new
550
+ context.set_params(@ssl_params)
551
+ s = OpenSSL::SSL::SSLSocket.new(s, context)
552
+ s.hostname = @address
553
+ s.sync_close = true
554
+ ssl_socket_connect(s, @open_timeout)
555
+ if context.verify_mode != OpenSSL::SSL::VERIFY_NONE
556
+ s.post_connection_check(@address)
557
+ end
558
+ end
559
+ @socket = InternetMessageIO.new(s,
560
+ read_timeout: @read_timeout,
561
+ debug_output: @debug_output)
562
+ logging "POP session started: #{@address}:#{@port} (#{@apop ? 'APOP' : 'POP'})"
563
+ on_connect
564
+ @command = POP3Command.new(@socket)
565
+ if apop?
566
+ @command.apop account, password
567
+ else
568
+ @command.auth account, password
569
+ end
570
+ @started = true
571
+ ensure
572
+ # Authentication failed, clean up connection.
573
+ unless @started
574
+ s.close if s
575
+ @socket = nil
576
+ @command = nil
577
+ end
578
+ end
579
+ private :do_start
580
+
581
+ # Does nothing
582
+ def on_connect # :nodoc:
583
+ end
584
+ private :on_connect
585
+
586
+ # Finishes a POP3 session and closes TCP connection.
587
+ def finish
588
+ raise IOError, 'POP session not yet started' unless started?
589
+ do_finish
590
+ end
591
+
592
+ # nil's out the:
593
+ # - mails
594
+ # - number counter for mails
595
+ # - number counter for bytes
596
+ # - quits the current command, if any
597
+ def do_finish # :nodoc:
598
+ @mails = nil
599
+ @n_mails = nil
600
+ @n_bytes = nil
601
+ @command.quit if @command
602
+ ensure
603
+ @started = false
604
+ @command = nil
605
+ @socket.close if @socket
606
+ @socket = nil
607
+ end
608
+ private :do_finish
609
+
610
+ # Returns the current command.
611
+ #
612
+ # Raises IOError if there is no active socket
613
+ def command # :nodoc:
614
+ raise IOError, 'POP session not opened yet' \
615
+ if not @socket or @socket.closed?
616
+ @command
617
+ end
618
+ private :command
619
+
620
+ #
621
+ # POP protocol wrapper
622
+ #
623
+
624
+ # Returns the number of messages on the POP server.
625
+ def n_mails
626
+ return @n_mails if @n_mails
627
+ @n_mails, @n_bytes = command().stat
628
+ @n_mails
629
+ end
630
+
631
+ # Returns the total size in bytes of all the messages on the POP server.
632
+ def n_bytes
633
+ return @n_bytes if @n_bytes
634
+ @n_mails, @n_bytes = command().stat
635
+ @n_bytes
636
+ end
637
+
638
+ # Returns an array of Net::POPMail objects, representing all the
639
+ # messages on the server. This array is renewed when the session
640
+ # restarts; otherwise, it is fetched from the server the first time
641
+ # this method is called (directly or indirectly) and cached.
642
+ #
643
+ # This method raises a POPError if an error occurs.
644
+ def mails
645
+ return @mails.dup if @mails
646
+ if n_mails() == 0
647
+ # some popd raises error for LIST on the empty mailbox.
648
+ @mails = []
649
+ return []
650
+ end
651
+
652
+ @mails = command().list.map {|num, size|
653
+ POPMail.new(num, size, self, command())
654
+ }
655
+ @mails.dup
656
+ end
657
+
658
+ # Yields each message to the passed-in block in turn.
659
+ # Equivalent to:
660
+ #
661
+ # pop3.mails.each do |popmail|
662
+ # ....
663
+ # end
664
+ #
665
+ # This method raises a POPError if an error occurs.
666
+ def each_mail(&block) # :yield: message
667
+ mails().each(&block)
668
+ end
669
+
670
+ alias each each_mail
671
+
672
+ # Deletes all messages on the server.
673
+ #
674
+ # If called with a block, yields each message in turn before deleting it.
675
+ #
676
+ # === Example
677
+ #
678
+ # n = 1
679
+ # pop.delete_all do |m|
680
+ # File.open("inbox/#{n}") do |f|
681
+ # f.write m.pop
682
+ # end
683
+ # n += 1
684
+ # end
685
+ #
686
+ # This method raises a POPError if an error occurs.
687
+ #
688
+ def delete_all # :yield: message
689
+ mails().each do |m|
690
+ yield m if block_given?
691
+ m.delete unless m.deleted?
692
+ end
693
+ end
694
+
695
+ # Resets the session. This clears all "deleted" marks from messages.
696
+ #
697
+ # This method raises a POPError if an error occurs.
698
+ def reset
699
+ command().rset
700
+ mails().each do |m|
701
+ m.instance_eval {
702
+ @deleted = false
703
+ }
704
+ end
705
+ end
706
+
707
+ def set_all_uids #:nodoc: internal use only (called from POPMail#uidl)
708
+ uidl = command().uidl
709
+ @mails.each {|m| m.uid = uidl[m.number] }
710
+ end
711
+
712
+ # debugging output for +msg+
713
+ def logging(msg)
714
+ @debug_output << msg + "\n" if @debug_output
715
+ end
716
+
717
+ end # class POP3
718
+
719
+ # class aliases
720
+ POP = POP3 # :nodoc:
721
+ POPSession = POP3 # :nodoc:
722
+ POP3Session = POP3 # :nodoc:
723
+
724
+ #
725
+ # This class is equivalent to POP3, except that it uses APOP authentication.
726
+ #
727
+ class APOP < POP3
728
+ # Always returns true.
729
+ def apop?
730
+ true
731
+ end
732
+ end
733
+
734
+ # class aliases
735
+ APOPSession = APOP
736
+
737
+ #
738
+ # This class represents a message which exists on the POP server.
739
+ # Instances of this class are created by the POP3 class; they should
740
+ # not be directly created by the user.
741
+ #
742
+ class POPMail
743
+
744
+ def initialize(num, len, pop, cmd) #:nodoc:
745
+ @number = num
746
+ @length = len
747
+ @pop = pop
748
+ @command = cmd
749
+ @deleted = false
750
+ @uid = nil
751
+ end
752
+
753
+ # The sequence number of the message on the server.
754
+ attr_reader :number
755
+
756
+ # The length of the message in octets.
757
+ attr_reader :length
758
+ alias size length
759
+
760
+ # Provide human-readable stringification of class state.
761
+ def inspect
762
+ +"#<#{self.class} #{@number}#{@deleted ? ' deleted' : ''}>"
763
+ end
764
+
765
+ #
766
+ # This method fetches the message. If called with a block, the
767
+ # message is yielded to the block one chunk at a time. If called
768
+ # without a block, the message is returned as a String. The optional
769
+ # +dest+ argument will be prepended to the returned String; this
770
+ # argument is essentially obsolete.
771
+ #
772
+ # === Example without block
773
+ #
774
+ # POP3.start('pop.example.com', 110,
775
+ # 'YourAccount', 'YourPassword') do |pop|
776
+ # n = 1
777
+ # pop.mails.each do |popmail|
778
+ # File.open("inbox/#{n}", 'w') do |f|
779
+ # f.write popmail.pop
780
+ # end
781
+ # popmail.delete
782
+ # n += 1
783
+ # end
784
+ # end
785
+ #
786
+ # === Example with block
787
+ #
788
+ # POP3.start('pop.example.com', 110,
789
+ # 'YourAccount', 'YourPassword') do |pop|
790
+ # n = 1
791
+ # pop.mails.each do |popmail|
792
+ # File.open("inbox/#{n}", 'w') do |f|
793
+ # popmail.pop do |chunk| ####
794
+ # f.write chunk
795
+ # end
796
+ # end
797
+ # n += 1
798
+ # end
799
+ # end
800
+ #
801
+ # This method raises a POPError if an error occurs.
802
+ #
803
+ def pop( dest = +'', &block ) # :yield: message_chunk
804
+ if block_given?
805
+ @command.retr(@number, &block)
806
+ nil
807
+ else
808
+ @command.retr(@number) do |chunk|
809
+ dest << chunk
810
+ end
811
+ dest
812
+ end
813
+ end
814
+
815
+ alias all pop #:nodoc: obsolete
816
+ alias mail pop #:nodoc: obsolete
817
+
818
+ # Fetches the message header and +lines+ lines of body.
819
+ #
820
+ # The optional +dest+ argument is obsolete.
821
+ #
822
+ # This method raises a POPError if an error occurs.
823
+ def top(lines, dest = +'')
824
+ @command.top(@number, lines) do |chunk|
825
+ dest << chunk
826
+ end
827
+ dest
828
+ end
829
+
830
+ # Fetches the message header.
831
+ #
832
+ # The optional +dest+ argument is obsolete.
833
+ #
834
+ # This method raises a POPError if an error occurs.
835
+ def header(dest = +'')
836
+ top(0, dest)
837
+ end
838
+
839
+ # Marks a message for deletion on the server. Deletion does not
840
+ # actually occur until the end of the session; deletion may be
841
+ # cancelled for _all_ marked messages by calling POP3#reset().
842
+ #
843
+ # This method raises a POPError if an error occurs.
844
+ #
845
+ # === Example
846
+ #
847
+ # POP3.start('pop.example.com', 110,
848
+ # 'YourAccount', 'YourPassword') do |pop|
849
+ # n = 1
850
+ # pop.mails.each do |popmail|
851
+ # File.open("inbox/#{n}", 'w') do |f|
852
+ # f.write popmail.pop
853
+ # end
854
+ # popmail.delete ####
855
+ # n += 1
856
+ # end
857
+ # end
858
+ #
859
+ def delete
860
+ @command.dele @number
861
+ @deleted = true
862
+ end
863
+
864
+ alias delete! delete #:nodoc: obsolete
865
+
866
+ # True if the mail has been deleted.
867
+ def deleted?
868
+ @deleted
869
+ end
870
+
871
+ # Returns the unique-id of the message.
872
+ # Normally the unique-id is a hash string of the message.
873
+ #
874
+ # This method raises a POPError if an error occurs.
875
+ def unique_id
876
+ return @uid if @uid
877
+ @pop.set_all_uids
878
+ @uid
879
+ end
880
+
881
+ alias uidl unique_id
882
+
883
+ def uid=(uid) #:nodoc: internal use only
884
+ @uid = uid
885
+ end
886
+
887
+ end # class POPMail
888
+
889
+
890
+ class POP3Command #:nodoc: internal use only
891
+
892
+ def initialize(sock)
893
+ @socket = sock
894
+ @error_occurred = false
895
+ res = check_response(critical { recv_response() })
896
+ @apop_stamp = res.slice(/<[!-~]+@[!-~]+>/)
897
+ end
898
+
899
+ attr_reader :socket
900
+
901
+ def inspect
902
+ +"#<#{self.class} socket=#{@socket}>"
903
+ end
904
+
905
+ def auth(account, password)
906
+ check_response_auth(critical {
907
+ check_response_auth(get_response('USER %s', account))
908
+ get_response('PASS %s', password)
909
+ })
910
+ end
911
+
912
+ def apop(account, password)
913
+ raise POPAuthenticationError, 'not APOP server; cannot login' \
914
+ unless @apop_stamp
915
+ check_response_auth(critical {
916
+ get_response('APOP %s %s',
917
+ account,
918
+ Digest::MD5.hexdigest(@apop_stamp + password))
919
+ })
920
+ end
921
+
922
+ def list
923
+ critical {
924
+ getok 'LIST'
925
+ list = []
926
+ @socket.each_list_item do |line|
927
+ m = /\A(\d+)[ \t]+(\d+)/.match(line) or
928
+ raise POPBadResponse, "bad response: #{line}"
929
+ list.push [m[1].to_i, m[2].to_i]
930
+ end
931
+ return list
932
+ }
933
+ end
934
+
935
+ def stat
936
+ res = check_response(critical { get_response('STAT') })
937
+ m = /\A\+OK\s+(\d+)\s+(\d+)/.match(res) or
938
+ raise POPBadResponse, "wrong response format: #{res}"
939
+ [m[1].to_i, m[2].to_i]
940
+ end
941
+
942
+ def rset
943
+ check_response(critical { get_response('RSET') })
944
+ end
945
+
946
+ def top(num, lines = 0, &block)
947
+ critical {
948
+ getok('TOP %d %d', num, lines)
949
+ @socket.each_message_chunk(&block)
950
+ }
951
+ end
952
+
953
+ def retr(num, &block)
954
+ critical {
955
+ getok('RETR %d', num)
956
+ @socket.each_message_chunk(&block)
957
+ }
958
+ end
959
+
960
+ def dele(num)
961
+ check_response(critical { get_response('DELE %d', num) })
962
+ end
963
+
964
+ def uidl(num = nil)
965
+ if num
966
+ res = check_response(critical { get_response('UIDL %d', num) })
967
+ return res.split(/ /)[1]
968
+ else
969
+ critical {
970
+ getok('UIDL')
971
+ table = {}
972
+ @socket.each_list_item do |line|
973
+ num, uid = line.split
974
+ table[num.to_i] = uid
975
+ end
976
+ return table
977
+ }
978
+ end
979
+ end
980
+
981
+ def quit
982
+ check_response(critical { get_response('QUIT') })
983
+ end
984
+
985
+ private
986
+
987
+ def getok(fmt, *fargs)
988
+ @socket.writeline sprintf(fmt, *fargs)
989
+ check_response(recv_response())
990
+ end
991
+
992
+ def get_response(fmt, *fargs)
993
+ @socket.writeline sprintf(fmt, *fargs)
994
+ recv_response()
995
+ end
996
+
997
+ def recv_response
998
+ @socket.readline
999
+ end
1000
+
1001
+ def check_response(res)
1002
+ raise POPError, res unless /\A\+OK/i =~ res
1003
+ res
1004
+ end
1005
+
1006
+ def check_response_auth(res)
1007
+ raise POPAuthenticationError, res unless /\A\+OK/i =~ res
1008
+ res
1009
+ end
1010
+
1011
+ def critical
1012
+ return '+OK dummy ok response' if @error_occurred
1013
+ begin
1014
+ return yield()
1015
+ rescue Exception
1016
+ @error_occurred = true
1017
+ raise
1018
+ end
1019
+ end
1020
+
1021
+ end # class POP3Command
1022
+
1023
+ end # module Net
@@ -0,0 +1,5 @@
1
+ module Net
2
+ class POP3
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "net/pop/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "net-pop"
7
+ spec.version = Net::POP3::VERSION
8
+ spec.authors = ["Hiroshi SHIBATA"]
9
+ spec.email = ["hsbt@ruby-lang.org"]
10
+
11
+ spec.summary = %q{Ruby client library for POP3.}
12
+ spec.description = %q{Ruby client library for POP3.}
13
+ spec.homepage = "https://github.com/ruby/net-pop"
14
+ spec.license = "BSD-2-Clause"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: net-pop
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Hiroshi SHIBATA
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-11-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Ruby client library for POP3.
14
+ email:
15
+ - hsbt@ruby-lang.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".travis.yml"
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - bin/console
27
+ - bin/setup
28
+ - lib/net/pop.rb
29
+ - lib/net/pop/version.rb
30
+ - net-pop.gemspec
31
+ homepage: https://github.com/ruby/net-pop
32
+ licenses:
33
+ - BSD-2-Clause
34
+ metadata:
35
+ homepage_uri: https://github.com/ruby/net-pop
36
+ source_code_uri: https://github.com/ruby/net-pop
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubygems_version: 3.0.3
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: Ruby client library for POP3.
56
+ test_files: []