nntp-client 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -17
- data/.rspec +2 -2
- data/Gemfile +8 -8
- data/LICENSE.txt +21 -21
- data/Rakefile +1 -1
- data/lib/nntp/article.rb +3 -0
- data/lib/nntp/connection.rb +1 -1
- data/lib/nntp/session.rb +42 -8
- data/lib/nntp/status.rb +6 -6
- data/lib/nntp/version.rb +1 -1
- data/spec/session_spec.rb +17 -0
- metadata +3 -6
- data/lib/NNTPClient.rb +0 -120
- data/lib/article.rb +0 -7
- data/lib/nntp/message.rb +0 -3
data/.gitignore
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
.bundle
|
4
|
-
.config
|
5
|
-
.yardoc
|
6
|
-
Gemfile.lock
|
7
|
-
InstalledFiles
|
8
|
-
_yardoc
|
9
|
-
coverage
|
10
|
-
doc/
|
11
|
-
lib/bundler/man
|
12
|
-
pkg
|
13
|
-
rdoc
|
14
|
-
spec/reports
|
15
|
-
test/tmp
|
16
|
-
test/version_tmp
|
17
|
-
tmp
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
data/.rspec
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
--format specdoc
|
2
|
-
--color
|
1
|
+
--format specdoc
|
2
|
+
--color
|
data/Gemfile
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in nntp.gemspec
|
4
|
-
gem 'rake'
|
5
|
-
gem "rspec"
|
6
|
-
gem "rspec-core"
|
7
|
-
gem "rspec-expectations"
|
8
|
-
gem "rspec-mocks"
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in nntp.gemspec
|
4
|
+
gem 'rake'
|
5
|
+
gem "rspec"
|
6
|
+
gem "rspec-core"
|
7
|
+
gem "rspec-expectations"
|
8
|
+
gem "rspec-mocks"
|
data/LICENSE.txt
CHANGED
@@ -1,22 +1,22 @@
|
|
1
|
-
Copyright (c) 2012 Michael Westbom
|
2
|
-
|
3
|
-
MIT License
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
1
|
+
Copyright (c) 2012 Michael Westbom
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
22
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/nntp/article.rb
ADDED
data/lib/nntp/connection.rb
CHANGED
@@ -7,7 +7,7 @@ module NNTP
|
|
7
7
|
# Most communication with an NNTP server happens in a back-and-forth
|
8
8
|
# style.
|
9
9
|
#
|
10
|
-
# The client sends a
|
10
|
+
# The client sends a article to the server. The server will respond with a status response, and sometimes with extra data. See {https://tools.ietf.org/html/rfc3977 RFC 3977} for more details.
|
11
11
|
#
|
12
12
|
# This class handles this communication by providing two methods,
|
13
13
|
# one for use when additional data is expected, and one for when it is not.
|
data/lib/nntp/session.rb
CHANGED
@@ -1,17 +1,22 @@
|
|
1
1
|
require "nntp/group"
|
2
|
-
require 'nntp/
|
2
|
+
require 'nntp/article'
|
3
3
|
|
4
4
|
module NNTP
|
5
5
|
# Most of the action happens here. This class describes the
|
6
6
|
# object the user interacts with the most.
|
7
7
|
# It is constructed by NNTP::open, but you can build your own
|
8
8
|
# if you like.
|
9
|
+
|
10
|
+
# @!attribute [r] article
|
11
|
+
# The current article pointed to by the server or nil if unset.
|
12
|
+
# @return [NNTP::Article, nil]
|
9
13
|
class Session
|
10
|
-
attr_reader :connection, :group
|
14
|
+
attr_reader :connection, :group, :article
|
11
15
|
# @option options [NNTP::Connection, NNTP::SSLConnection] :connection
|
12
16
|
# The connection object.
|
13
17
|
def initialize(options)
|
14
18
|
@group = nil
|
19
|
+
@article = nil
|
15
20
|
@connection = options.fetch(:connection) do
|
16
21
|
raise ArgumentError ":connection missing"
|
17
22
|
end
|
@@ -51,18 +56,18 @@ module NNTP
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
# Fetch list of
|
59
|
+
# Fetch list of article numbers from a given group.
|
55
60
|
# @param group The name of the group to list defaults to {#group #group.name}
|
56
61
|
# @param range (nil) If given, specifies the range of messages to retrieve
|
57
|
-
# @return [Array<NNTP::
|
58
|
-
# (only the
|
62
|
+
# @return [Array<NNTP::Article>] The list of messages
|
63
|
+
# (only the article numbers will be populated).
|
59
64
|
# @see https://tools.ietf.org/html/rfc3977#section-6.1.2
|
60
65
|
def listgroup(*args)
|
61
66
|
messages = []
|
62
67
|
connection.query(:listgroup, *args) do |status, data|
|
63
68
|
if status[:code] == 211
|
64
69
|
data.each do |line|
|
65
|
-
message =
|
70
|
+
message = Article.new
|
66
71
|
message.num = line.to_i
|
67
72
|
messages << message
|
68
73
|
end
|
@@ -71,8 +76,29 @@ module NNTP
|
|
71
76
|
messages
|
72
77
|
end
|
73
78
|
|
79
|
+
# Fetch ID and/or Number of an article.
|
80
|
+
#
|
81
|
+
# If an article number is passed, the current article is changed
|
82
|
+
# to the selected article. If an ID is passed, the current article
|
83
|
+
# is NOT changed.
|
84
|
+
# @param id|num The article-id or article number to be selected.
|
85
|
+
# @return [NNTP::Article, nil] a Article struct or nil upon failure.
|
86
|
+
def stat(identifier = nil)
|
87
|
+
params = [:stat]
|
88
|
+
params += [identifier.to_s] unless identifier.nil?
|
89
|
+
connection.command(*params)
|
90
|
+
if status.code == 223
|
91
|
+
message = article_from_status(status.msg)
|
92
|
+
if identifier.to_i != 0
|
93
|
+
@article = message
|
94
|
+
end
|
95
|
+
message
|
96
|
+
else
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
end
|
74
100
|
# Fetch list of messages from current group.
|
75
|
-
# @return [Array<NNTP::
|
101
|
+
# @return [Array<NNTP::Article>] The list of messages
|
76
102
|
# (The numbers AND the subjects will be populated).
|
77
103
|
def subjects
|
78
104
|
subjects = []
|
@@ -80,7 +106,7 @@ module NNTP
|
|
80
106
|
connection.query(:xhdr, "Subject", range) do |status, data|
|
81
107
|
if status[:code] == 221
|
82
108
|
data.each do |line|
|
83
|
-
message =
|
109
|
+
message = Article.new
|
84
110
|
message.num, message.subject = line.split(' ', 2)
|
85
111
|
subjects << message
|
86
112
|
end
|
@@ -108,6 +134,14 @@ module NNTP
|
|
108
134
|
end
|
109
135
|
end
|
110
136
|
|
137
|
+
def article_from_status(status_msg)
|
138
|
+
message = Article.new
|
139
|
+
num, id = status_msg.split(' ', 2)
|
140
|
+
message.num = num.to_i unless num.to_i.zero?
|
141
|
+
message.id = id
|
142
|
+
message
|
143
|
+
end
|
144
|
+
|
111
145
|
def check_initial_status
|
112
146
|
raise "#{status}" if [400, 502].include? connection.get_status.code
|
113
147
|
end
|
data/lib/nntp/status.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
module NNTP
|
2
|
-
Status = Struct.new(:code, :msg) do
|
3
|
-
def to_s
|
4
|
-
"#{self[:code]} #{self[:msg]}"
|
5
|
-
end
|
6
|
-
end
|
1
|
+
module NNTP
|
2
|
+
Status = Struct.new(:code, :msg) do
|
3
|
+
def to_s
|
4
|
+
"#{self[:code]} #{self[:msg]}"
|
5
|
+
end
|
6
|
+
end
|
7
7
|
end
|
data/lib/nntp/version.rb
CHANGED
data/spec/session_spec.rb
CHANGED
@@ -100,4 +100,21 @@ describe NNTP::Session do
|
|
100
100
|
message_subjects(nntp.subjects).should eq ['Foo bar', 'Baz bang']
|
101
101
|
end
|
102
102
|
end
|
103
|
+
describe "#stat" do
|
104
|
+
let(:article) do
|
105
|
+
msg = NNTP::Article.new
|
106
|
+
msg.num = 1
|
107
|
+
msg.id = "<foo@bar.baz>"
|
108
|
+
msg
|
109
|
+
end
|
110
|
+
|
111
|
+
it "can set the current article using an article number" do
|
112
|
+
sock.should_receive(:print).with("STAT 1\r\n")
|
113
|
+
sock.should_receive(:gets).and_return("223 1 <foo@bar.baz>\r\n")
|
114
|
+
nntp.stub(:group) {NNTP::Group.new("alt.bin.foo", 1, 2, 2)}
|
115
|
+
nntp.stat(1)
|
116
|
+
nntp.status.should eq NNTP::Status.new(223, "1 <foo@bar.baz>")
|
117
|
+
nntp.article.should eq article
|
118
|
+
end
|
119
|
+
end
|
103
120
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nntp-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -40,12 +40,10 @@ files:
|
|
40
40
|
- LICENSE.txt
|
41
41
|
- README.md
|
42
42
|
- Rakefile
|
43
|
-
- lib/NNTPClient.rb
|
44
|
-
- lib/article.rb
|
45
43
|
- lib/nntp.rb
|
44
|
+
- lib/nntp/article.rb
|
46
45
|
- lib/nntp/connection.rb
|
47
46
|
- lib/nntp/group.rb
|
48
|
-
- lib/nntp/message.rb
|
49
47
|
- lib/nntp/session.rb
|
50
48
|
- lib/nntp/ssl_connection.rb
|
51
49
|
- lib/nntp/status.rb
|
@@ -87,4 +85,3 @@ test_files:
|
|
87
85
|
- spec/nntp_spec.rb
|
88
86
|
- spec/session_spec.rb
|
89
87
|
- spec/spec_helper.rb
|
90
|
-
has_rdoc:
|
data/lib/NNTPClient.rb
DELETED
@@ -1,120 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require_relative 'group'
|
3
|
-
require_relative 'article'
|
4
|
-
require "NNTPClient/version"
|
5
|
-
|
6
|
-
class NNTPClient
|
7
|
-
attr_reader :socket, :status, :current_group
|
8
|
-
|
9
|
-
def initialize(options = {})
|
10
|
-
@socket = open_socket(options)
|
11
|
-
init_attributes
|
12
|
-
end
|
13
|
-
|
14
|
-
def groups
|
15
|
-
@groups ||= list_groups
|
16
|
-
end
|
17
|
-
|
18
|
-
def group(group)
|
19
|
-
send_message "GROUP #{group}"
|
20
|
-
self.status = get_status
|
21
|
-
if status[:code] == 211
|
22
|
-
self.current_group = create_group(status)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def articles
|
27
|
-
@articles ||= fetch_articles
|
28
|
-
end
|
29
|
-
|
30
|
-
def auth(options = {})
|
31
|
-
send_message "AUTHINFO USER #{options[:user]}"
|
32
|
-
self.status = get_status
|
33
|
-
send_message "AUTHINFO PASS #{options[:pass]}"
|
34
|
-
self.status = get_status
|
35
|
-
if status[:code] == 281
|
36
|
-
true
|
37
|
-
else
|
38
|
-
false
|
39
|
-
end
|
40
|
-
end
|
41
|
-
private
|
42
|
-
def fetch_articles
|
43
|
-
send_message "XHDR Subject #{current_group.first}-"
|
44
|
-
self.status = get_status
|
45
|
-
return nil unless status[:code] == 221
|
46
|
-
get_data_block.map do |line|
|
47
|
-
article_id, article_subject = line.split(' ', 2)
|
48
|
-
NNTP::Article.new(article_id, article_subject)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def init_attributes
|
53
|
-
@current_group = nil
|
54
|
-
@status = nil
|
55
|
-
@groups = nil
|
56
|
-
@articles = nil
|
57
|
-
end
|
58
|
-
|
59
|
-
def create_group(status)
|
60
|
-
params = status[:params]
|
61
|
-
# TODO: This is ugly
|
62
|
-
NNTP::Group.new(*params[1..-1])
|
63
|
-
end
|
64
|
-
|
65
|
-
def open_socket(options)
|
66
|
-
options.fetch(:socket) {
|
67
|
-
url = options.fetch(:url) { raise ArgumentError, ':url is required' }
|
68
|
-
port = options.fetch(:port, 119)
|
69
|
-
socket_factory = options.fetch(:socket_factory) { TCPSocket }
|
70
|
-
socket_factory.new(url, port)
|
71
|
-
}
|
72
|
-
end
|
73
|
-
|
74
|
-
def list_groups
|
75
|
-
send_message "LIST"
|
76
|
-
status = get_status
|
77
|
-
return nil unless status[:code] == 215
|
78
|
-
|
79
|
-
get_data_block
|
80
|
-
end
|
81
|
-
|
82
|
-
def groups=(list=[])
|
83
|
-
@groups = list
|
84
|
-
end
|
85
|
-
|
86
|
-
def status=(status)
|
87
|
-
@status = status
|
88
|
-
end
|
89
|
-
|
90
|
-
def current_group=(group)
|
91
|
-
@current_group = group
|
92
|
-
end
|
93
|
-
|
94
|
-
def get_status
|
95
|
-
line = get_line
|
96
|
-
{
|
97
|
-
:code => line[0..2].to_i,
|
98
|
-
:message => line[3..-1].lstrip,
|
99
|
-
:params => line.split
|
100
|
-
}
|
101
|
-
end
|
102
|
-
|
103
|
-
def get_data_block
|
104
|
-
lines = []
|
105
|
-
current_line = get_line
|
106
|
-
until current_line == '.'
|
107
|
-
lines << current_line
|
108
|
-
current_line = get_line
|
109
|
-
end
|
110
|
-
lines
|
111
|
-
end
|
112
|
-
|
113
|
-
def get_line
|
114
|
-
socket.gets().chomp
|
115
|
-
end
|
116
|
-
|
117
|
-
def send_message(msg)
|
118
|
-
socket.print "#{msg}\r\n"
|
119
|
-
end
|
120
|
-
end
|
data/lib/article.rb
DELETED
data/lib/nntp/message.rb
DELETED