ruby-net-nntp 0.0.7 → 0.0.8
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/CHANGELOG +12 -1
- data/lib/net/nntp.rb +345 -336
- data/lib/net/nntp/version.rb +1 -1
- data/lib/net/nntp_article.rb +22 -22
- data/lib/net/nntp_group.rb +61 -61
- data/test/functional/test_nntp.rb +229 -229
- data/test/mock/mock_socket.rb +213 -213
- data/test/unit/test_nntp_group.rb +1 -1
- metadata +3 -3
data/lib/net/nntp/version.rb
CHANGED
data/lib/net/nntp_article.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
module Net
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
class NNTP
|
3
|
+
class Article
|
4
|
+
attr_accessor :id, :messageid, :subject, :group
|
5
|
+
attr_reader :overview_format, :bytes, :lines, :xref, :date, :from
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
def initialize
|
8
|
+
@overview_format = %w{id}
|
9
|
+
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
def overview_format=(format)
|
12
|
+
if Array === format
|
13
|
+
@overview_format = format
|
14
|
+
else
|
15
|
+
@overview_format = Net::NNTP.parse_overview_format format
|
16
|
+
end
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
def overview(over)
|
20
|
+
over.split(/\t/).each_with_index do |value, index|
|
21
|
+
ident = @overview_format[index]
|
22
|
+
eval "@#{ident} = value;"
|
23
|
+
end
|
24
|
+
end
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
end
|
27
|
+
end
|
28
28
|
end
|
data/lib/net/nntp_group.rb
CHANGED
@@ -1,76 +1,76 @@
|
|
1
1
|
module Net
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
3
|
+
class NNTP
|
4
|
+
|
5
|
+
class Group
|
6
|
+
attr_reader :name, :article_count, :article_first, :article_last
|
7
|
+
attr_reader :hi, :lo, :postingmode
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@name = name
|
11
|
+
@articles ||= Articles.new(self)
|
12
|
+
#@articles.group = self
|
13
|
+
@article_first = @article_last = @article_count = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def article_info=(art_array)
|
17
|
+
@article_count = art_array[0].to_i
|
18
|
+
@article_first = art_array[1].to_i
|
19
|
+
@article_last = art_array[2].to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
def articles
|
23
|
+
@articles
|
24
|
+
end
|
25
|
+
|
26
|
+
def articles=(articles)
|
27
|
+
@articles = articles
|
28
|
+
end
|
29
|
+
|
30
|
+
def listinfo(hi, lo, postingmode)
|
31
|
+
@hi = hi
|
32
|
+
@lo = lo
|
33
|
+
@postingmode = postingmode
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
37
|
"Group: #{@name} #{@article_count} #{@article_first} #{@article_last}"
|
38
|
-
|
38
|
+
end
|
39
39
|
|
40
|
-
|
40
|
+
class Articles
|
41
41
|
|
42
|
-
|
42
|
+
attr_accessor :group
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
def initialize(group)
|
45
|
+
@articles ||=[]
|
46
|
+
end
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
def build_from_over(over, format)
|
49
|
+
article = Article.new
|
50
|
+
article.overview_format = format
|
51
|
+
article.overview(over)
|
52
|
+
@articles << article
|
53
|
+
end
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
def length
|
56
|
+
@articles.length
|
57
|
+
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
def <<(article)
|
60
|
+
@articles << article
|
61
|
+
end
|
62
62
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
63
|
+
def create
|
64
|
+
a = Article.new
|
65
|
+
a.group = self.group
|
66
|
+
@articles << a
|
67
|
+
a
|
68
|
+
end
|
69
69
|
|
70
|
-
|
70
|
+
end
|
71
71
|
|
72
|
-
|
72
|
+
end
|
73
73
|
|
74
|
-
|
74
|
+
end
|
75
75
|
|
76
76
|
end
|
@@ -6,257 +6,257 @@ require 'mock/mock_socket'
|
|
6
6
|
|
7
7
|
|
8
8
|
module TestNet
|
9
|
-
|
9
|
+
class TestNNTP < Test::Unit::TestCase
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
def setup
|
12
|
+
unless @log
|
13
|
+
@log = Log4r::Logger.new('net::nntp')
|
14
|
+
fileout = Log4r::FileOutputter.new('net::nntp::fileout', :filename => File.join('logs', 'autotest.log'))
|
15
|
+
fileout.formatter = Log4r::PatternFormatter.new(:pattern => '%d [%5l] : %m')
|
16
|
+
@log.add fileout
|
17
|
+
@log.level = Log4r::ALL
|
18
|
+
end
|
19
|
+
nntp_connect_and_auth('localhost', 119, 'dummy', 'test')
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
22
|
+
def test_new
|
23
|
+
host = 'localhost'
|
24
|
+
port = '119'
|
25
|
+
assert_nothing_raised do
|
26
|
+
@nntp = Net::NNTP.new(host)
|
27
|
+
end
|
28
|
+
assert_nothing_raised do
|
29
|
+
nntp_new(host, port)
|
30
|
+
end
|
31
|
+
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
def test_connect
|
34
|
+
assert_nothing_raised do
|
35
|
+
@nntp.connect
|
36
|
+
end
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
39
|
+
def test_help
|
40
|
+
help = @nntp.help.join
|
41
|
+
assert_equal '100', help[0..2]
|
42
|
+
assert_equal 429, help.length
|
43
|
+
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
def test_authenticate
|
46
|
+
assert_nothing_raised do
|
47
|
+
assert nntp_connect_and_auth('localhost', 119, 'dummy', 'test')
|
48
|
+
end
|
49
|
+
end
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
51
|
+
def test_group
|
52
|
+
assert_nothing_raised do
|
53
|
+
group = @nntp.group('at.linux')
|
54
|
+
assert_kind_of Net::NNTP::Group, group
|
55
|
+
assert_equal 'at.linux', group.name
|
56
|
+
assert_equal 12, group.article_count
|
57
|
+
assert_equal 1363, group.article_first
|
58
|
+
assert_equal 1375, group.article_last
|
59
|
+
end
|
60
|
+
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
62
|
+
def test_xhdr
|
63
|
+
headers = @nntp.xhdr('subject', 'at.linux', :from => 1363, :to => 1375)
|
64
|
+
assert_equal 15, headers.length
|
65
|
+
assert_equal '221', headers[0][0..2]
|
66
|
+
assert_equal "1364", headers[2].split[0]
|
67
|
+
header = @nntp.xhdr('subject', 'at.linux', :message_id => "<slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>").join
|
68
|
+
assert_equal 47, header.length
|
69
|
+
assert_equal "1375", header.split[0]
|
70
|
+
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
72
|
+
def test_xhdr_fails
|
73
|
+
header = @nntp.xhdr('', 'at.linux', {}).join
|
74
|
+
assert_equal '502', header[0..2]
|
75
|
+
assert_raise(Net::NNTP::CommandFailedError) do
|
76
|
+
header = @nntp.xhdr('at.xxx', 'subject', {})
|
77
|
+
end
|
78
|
+
end
|
79
79
|
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
81
|
+
def test_group_fails
|
82
|
+
assert_raise(Net::NNTP::CommandFailedError) do
|
83
|
+
group = @nntp.group('at.xxx')
|
84
|
+
end
|
85
|
+
end
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
87
|
+
def test_xover
|
88
|
+
overviews = @nntp.xover('at.linux', :from => 1363, :to => 1375)
|
89
|
+
assert_equal 15, overviews.length
|
90
|
+
assert_equal '224', overviews[0][0..2]
|
91
|
+
end
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
def test_over_or_xover
|
94
|
+
assert @nntp.has_xover?
|
95
|
+
assert @nntp.has_over?
|
96
|
+
end
|
97
97
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
98
|
+
def test_xover_fails
|
99
|
+
over = @nntp.xover('at.linux', :from => 1363, :to => 1375)
|
100
|
+
over = @nntp.xover('at.linux', :message_id => "<slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>").join
|
101
|
+
assert_equal '502', over[0..2]
|
102
|
+
assert_raises(Net::NNTP::CommandFailedError) do
|
103
|
+
over = @nntp.xover('at.xxx', :message_id => "<slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>")
|
104
|
+
end
|
105
|
+
end
|
106
106
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
107
|
+
def test_listgroup
|
108
|
+
list = @nntp.listgroup('at.linux')
|
109
|
+
assert_equal 15, list.length
|
110
|
+
match = /(\d{3}).*f\or\s+(\S+)\s/.match(list[0])
|
111
|
+
assert_equal "211", match[1]
|
112
|
+
assert_equal "at.linux", match[2]
|
113
|
+
assert_equal "1365", list[3]
|
114
|
+
end
|
115
115
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
116
|
+
def test_list
|
117
|
+
assert_respond_to @nntp, :list
|
118
|
+
assert_nothing_raised do
|
119
|
+
@nntp.list('overview.fmt')
|
120
|
+
assert_equal 9, @nntp.overview_format.length
|
121
|
+
@nntp.list()
|
122
|
+
assert_not_equal 0, @nntp.grouplist.length
|
123
|
+
assert_not_nil @nntp.grouplist
|
124
|
+
assert_equal 'at.test', @nntp.grouplist['at.test'].name
|
125
|
+
@nntp.list('active')
|
126
|
+
assert_equal 'at.test', @nntp.grouplist['at.test'].name
|
127
|
+
@nntp.list('active.times')
|
128
|
+
@nntp.list('active.times', 'at.*')
|
129
|
+
end
|
130
|
+
assert_raise Net::NNTP::CommandFailedError do
|
131
|
+
@nntp.list('distrib.pat', 'at.*')
|
132
|
+
end
|
133
|
+
end
|
134
134
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
135
|
+
def test_article
|
136
|
+
assert_raises Net::NNTP::CommandFailedError do
|
137
|
+
article = @nntp.article
|
138
|
+
end
|
139
|
+
article = @nntp.article("<5d6be$4625ae23$51df8a12$32566@news.inode.at>")
|
140
|
+
response, id, msgid = article[0].split
|
141
|
+
assert_equal '220', response
|
142
|
+
assert_equal '1392', id
|
143
|
+
assert_equal "<5d6be$4625ae23$51df8a12$32566@news.inode.at>", msgid
|
144
|
+
group = @nntp.group 'at.linux'
|
145
|
+
article = @nntp.article '1392'
|
146
|
+
response, id, msgid = article[0].split
|
147
|
+
assert_equal '220', response
|
148
|
+
assert_equal '1392', id
|
149
|
+
assert_equal "<5d6be$4625ae23$51df8a12$32566@news.inode.at>", msgid
|
150
|
+
end
|
151
151
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
152
|
+
def test_head
|
153
|
+
nntp_connect_and_auth('localhost', 119, 'dummy', 'test')
|
154
|
+
assert_nothing_raised do
|
155
|
+
assert_respond_to @nntp, :head
|
156
|
+
end
|
157
|
+
assert_raise Net::NNTP::CommandFailedError do
|
158
|
+
head = @nntp.head
|
159
|
+
end
|
160
|
+
@nntp.group 'at.linux'
|
161
|
+
@io = [
|
162
|
+
"221 1430 <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net> article retrieved - head follows\r\n",
|
163
|
+
"Path: vietwist00.chello.at!newsfeed02.chello.at!newsfeed01.chello.at!newsfeed.arcor.de!newsspool1.arcor-online.net!news.arcor.de.POSTED!not-for-mail\r\n",
|
164
|
+
"Message-ID: <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net>\r\n",
|
165
|
+
"From: Gerhard Engler <gerhard.engler@gmx.de>\r\n",
|
166
|
+
"Newsgroups: at.linux\r\n",
|
167
|
+
"Subject: Re: udev_node_mknod: /dev/capi Operation not permitted\r\n",
|
168
|
+
"Date: Tue, 24 Apr 2007 14:39:11 +0200\r\n",
|
169
|
+
"References: <4629ee10$0$10187$9b4e6d93@newsspool4.arcor-online.net> <slrnf2np7k.a8e.tom-usenet@eristoteles.iwoars.net>\r\n",
|
170
|
+
"Lines: 26\r\n",
|
171
|
+
"User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)\r\n",
|
172
|
+
"MIME-Version: 1.0\r\n",
|
173
|
+
"In-Reply-To: <slrnf2np7k.a8e.tom-usenet@eristoteles.iwoars.net>\r\n",
|
174
|
+
"Content-Type: text/plain; charset=ISO-8859-15; format=flowed\r\n",
|
175
|
+
"Content-Transfer-Encoding: 7bit\r\n",
|
176
|
+
"Organization: Arcor\r\n",
|
177
|
+
"NNTP-Posting-Date: 24 Apr 2007 14:39:11 CEST\r\n",
|
178
|
+
"NNTP-Posting-Host: 6cf11d8c.newsspool1.arcor-online.net\r\n",
|
179
|
+
"X-Trace: DXC=Cd=D_AR>:`a^Y=RbYBPl4`ic==]BZ:afn4Fo<]lROoRaFl8W>\BH3Yb7K@fQgPi`FgUTEAfnAR\Ta@JWJ8E:^d<ob]cIfD6hVgh<SdIn0f]3?i\r\n",
|
180
|
+
"X-Complaints-To: usenet-abuse@arcor.de\r\n",
|
181
|
+
"Xref: sensor.twincode.net at.linux:1430\r\n",
|
182
|
+
".\r\n"
|
183
|
+
]
|
184
|
+
head = @nntp.head
|
185
|
+
assert_kind_of Array, head
|
186
|
+
response, id, msgid = head[0].split
|
187
|
+
assert_equal '221', response
|
188
|
+
assert_equal '1430', id
|
189
|
+
assert_equal '<462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net>', msgid
|
190
|
+
end
|
191
191
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
192
|
+
def test_body
|
193
|
+
assert_raises Net::NNTP::CommandFailedError do
|
194
|
+
body = @nntp.body
|
195
|
+
end
|
196
|
+
body = @nntp.body("<5d6be$4625ae23$51df8a12$32566@news.inode.at>")
|
197
|
+
response, id, msgid = body[0].split
|
198
|
+
assert_equal '222', response
|
199
|
+
assert_equal '1392', id
|
200
|
+
assert_equal "<5d6be$4625ae23$51df8a12$32566@news.inode.at>", msgid
|
201
|
+
group = @nntp.group 'at.linux'
|
202
|
+
body = @nntp.body '1392'
|
203
|
+
response, id, msgid = body[0].split
|
204
|
+
assert_equal '222', response
|
205
|
+
assert_equal '1392', id
|
206
|
+
assert_equal "<5d6be$4625ae23$51df8a12$32566@news.inode.at>", msgid
|
207
|
+
end
|
208
208
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
209
|
+
def test_stat
|
210
|
+
assert_nothing_raised do
|
211
|
+
assert_respond_to @nntp, :stat
|
212
|
+
end
|
213
|
+
end
|
214
214
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
215
|
+
def test_last
|
216
|
+
assert_raise Net::NNTP::ProtocolError do
|
217
|
+
last = @nntp.last
|
218
|
+
end
|
219
|
+
@nntp.group 'at.linux'
|
220
|
+
assert_raise Net::NNTP::CommandFailedError do
|
221
|
+
last = @nntp.last
|
222
|
+
end
|
223
|
+
@nntp.next
|
224
|
+
@nntp.next
|
225
|
+
last = @nntp.last
|
226
|
+
assert_kind_of String, last
|
227
|
+
response, article, msgid, rest = last.split
|
228
|
+
assert_equal "223", response
|
229
|
+
assert_equal "1363", article
|
230
|
+
end
|
231
231
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
232
|
+
def test_next
|
233
|
+
assert_raise Net::NNTP::ProtocolError do
|
234
|
+
anext = @nntp.next
|
235
|
+
end
|
236
|
+
@nntp.group 'at.linux'
|
237
|
+
anext = @nntp.next
|
238
|
+
assert_kind_of String, anext
|
239
|
+
response, article, msgid, rest = anext.split
|
240
|
+
assert_equal "223", response
|
241
|
+
assert_equal "1363", article
|
242
|
+
assert_equal "<example.msgid@fake.host>", msgid
|
243
|
+
anext = @nntp.next
|
244
|
+
response, article, msgid, rest = anext.split
|
245
|
+
assert_equal "1364", article
|
246
|
+
end
|
247
247
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
248
|
+
private
|
249
|
+
def nntp_new(host, port=119)
|
250
|
+
@nntp = Net::NNTP.new(host, port)
|
251
|
+
end
|
252
|
+
def nntp_connect_and_auth(host, port, user, pass)
|
253
|
+
@nntp = Net::NNTP.new(host, port)
|
254
|
+
@nntp.instance_variable_set :@socket_class, MockSocket
|
255
|
+
@nntp.connect
|
256
|
+
@nntp.socket.activate
|
257
|
+
@nntp.authenticate(user, pass)
|
258
|
+
end
|
259
|
+
end
|
260
260
|
end
|
261
261
|
|
262
262
|
|