ruby-net-nntp 0.0.2
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 +14 -0
- data/MIT-LICENSE +23 -0
- data/README +31 -0
- data/lib/net/nntp.rb +286 -0
- data/lib/net/nntp_article.rb +24 -0
- data/lib/net/nntp_group.rb +76 -0
- data/test/functional/test_nntp.rb +249 -0
- data/test/mock/mock_socket.rb +330 -0
- data/test/unit/test_nntp_article.rb +56 -0
- data/test/unit/test_nntp_group.rb +60 -0
- metadata +70 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
2007-05-17 08:09 +0200 Anton 'tony' Bangratz <tony@twincode.net> (702e55388bb4 [tip])
|
2
|
+
|
3
|
+
* .hgtags:
|
4
|
+
tags fix
|
5
|
+
|
6
|
+
2007-05-17 08:00 +0200 Anton 'tony' Bangratz <tony@twincode.net> (63ed2815f13f)
|
7
|
+
|
8
|
+
* .autotest, .hgignore, .hgtags, .in.vim, MIT-LICENSE, README,
|
9
|
+
Rakefile, lib/net/nntp.rb, lib/net/nntp_article.rb,
|
10
|
+
lib/net/nntp_group.rb, tags, test/functional/test_nntp.rb,
|
11
|
+
test/mock/mock_socket.rb, test/unit/test_nntp_article.rb,
|
12
|
+
test/unit/test_nntp_group.rb:
|
13
|
+
Safe commit
|
14
|
+
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
= MIT LICENSE
|
2
|
+
|
3
|
+
Copyright (c) 2007 Anton Bangratz
|
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
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
data/README
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
libruby-nntp
|
2
|
+
by Anton Bangratz
|
3
|
+
|
4
|
+
== DESCRIPTION
|
5
|
+
|
6
|
+
The Net::NNTP library provides a simple communication layer for the NNTP (Network News Transfer Protocol).
|
7
|
+
|
8
|
+
== FEATURES
|
9
|
+
|
10
|
+
The Net::NNTP library provides a communication layer in Net::XXX style for NNTP.
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
== SYNOPSIS
|
15
|
+
|
16
|
+
Net::NNTP uses a simple interface to wrap commands to communicate with an NNTP server.
|
17
|
+
|
18
|
+
=== Example
|
19
|
+
|
20
|
+
nntp = Net::NNTP.new('localhost')
|
21
|
+
if nntp.authenticate('user', 'xxxx')
|
22
|
+
nntp.group 'alt.test'
|
23
|
+
if nntp.next
|
24
|
+
article = nntp.article
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
== INSTALL
|
29
|
+
|
30
|
+
* sudo gem install libruby-nntp or
|
31
|
+
* sudo dpkg -r libruby-0.0.1.deb
|
data/lib/net/nntp.rb
ADDED
@@ -0,0 +1,286 @@
|
|
1
|
+
# = Net::NNTP class
|
2
|
+
# Author:: Anton Bangratz
|
3
|
+
require 'socket'
|
4
|
+
require 'thread'
|
5
|
+
require 'timeout' # :nodoc:
|
6
|
+
require 'net/nntp_group'
|
7
|
+
require 'net/nntp_article'
|
8
|
+
|
9
|
+
|
10
|
+
module Net
|
11
|
+
class NNTP
|
12
|
+
VERSION = "0.0.2"
|
13
|
+
include Timeout # :nodoc:
|
14
|
+
|
15
|
+
# Error to indicate that NNTP Command failed gracefully
|
16
|
+
class CommandFailedError < StandardError
|
17
|
+
end
|
18
|
+
# Error to indicate that a Protocol Error occured during NNTP command execution
|
19
|
+
class ProtocolError < StandardError
|
20
|
+
end
|
21
|
+
attr_reader :socket, :grouplist, :overview_format
|
22
|
+
|
23
|
+
# initializes NNTP class with host and port
|
24
|
+
def initialize(host, port = 119)
|
25
|
+
@host = host
|
26
|
+
@port = port
|
27
|
+
@socket_class = TCPSocket
|
28
|
+
@group = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# Actually connects to NNTP host and port given in new()
|
32
|
+
def connect
|
33
|
+
@socket = @socket_class.new(@host, @port)
|
34
|
+
@welcome = @socket.recv 1024
|
35
|
+
end
|
36
|
+
|
37
|
+
# Uses authinfo commands to authenticate. Timeout for first command is set to 10 seconds.
|
38
|
+
#
|
39
|
+
# Returns true on success, false on failure.
|
40
|
+
def authenticate(user, pass)
|
41
|
+
cmd = "authinfo user #{user}"
|
42
|
+
send_cmd cmd
|
43
|
+
response = nil
|
44
|
+
timeout(10) do
|
45
|
+
response = @socket.recv 1024
|
46
|
+
end
|
47
|
+
if response[0..2] == '381' then
|
48
|
+
cmd = "authinfo pass #{pass}"
|
49
|
+
send_cmd cmd
|
50
|
+
response = @socket.recv 1024
|
51
|
+
end
|
52
|
+
return response && response[0..2] == '281'
|
53
|
+
end
|
54
|
+
|
55
|
+
# Issues 'GROUP' command to NNTP Server and creates new active group from returning data.
|
56
|
+
#
|
57
|
+
# Throws CommandFailedError
|
58
|
+
#
|
59
|
+
def group(group)
|
60
|
+
send_cmd "group #{group}"
|
61
|
+
response = @socket.readline
|
62
|
+
responsecode, cnt, first, last, name = response.split
|
63
|
+
if responsecode == '211'
|
64
|
+
@group = Group.new(name)
|
65
|
+
@group.article_info = [cnt, first, last]
|
66
|
+
@group
|
67
|
+
else
|
68
|
+
raise CommandFailedError, response
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Issues 'HELP' command to NNTP Server, and returns raw response.
|
73
|
+
def help
|
74
|
+
send_cmd("help")
|
75
|
+
read_response()
|
76
|
+
end
|
77
|
+
|
78
|
+
# Issues 'XHDR' command to NNTP Server, and returns raw response. Checks if group has been selected, selects group
|
79
|
+
# otherwise.
|
80
|
+
#
|
81
|
+
# TODO:: Implement XHDR header <message-id>
|
82
|
+
def xhdr(groupname, header, rest)
|
83
|
+
group(groupname) unless (@group && @group.name == groupname)
|
84
|
+
cmd = "xhdr #{header}"
|
85
|
+
suffix = numbers_or_id(rest)
|
86
|
+
send_cmd([cmd, suffix].join(' '))
|
87
|
+
read_response()
|
88
|
+
end
|
89
|
+
|
90
|
+
# Issues 'XOVER' command to NNTP Server, and returns raw response. Checks if group has been selected, selects group
|
91
|
+
# otherwise.
|
92
|
+
#
|
93
|
+
def xover(groupname, rest)
|
94
|
+
group(groupname) unless (@group && @group.name == groupname)
|
95
|
+
prefix = "xover"
|
96
|
+
suffix = numbers_or_id(rest)
|
97
|
+
cmd = [prefix, suffix].join ' '
|
98
|
+
send_cmd(cmd)
|
99
|
+
read_response()
|
100
|
+
end
|
101
|
+
|
102
|
+
# Issues 'LISTGROUP' command to NNTP Server, and returns raw response. Checks if group has been selected, selects group
|
103
|
+
# otherwise.
|
104
|
+
#
|
105
|
+
def listgroup(groupname)
|
106
|
+
group(groupname) unless (@group && @group.name == groupname)
|
107
|
+
send_cmd('listgroup')
|
108
|
+
read_response()
|
109
|
+
end
|
110
|
+
|
111
|
+
# Issues 'LIST' command to NNTP Server. Depending on server capabilities and given keyword, can either set overview
|
112
|
+
# format (if called with 'overview.fmt') or create a grouplist (see Attributes)
|
113
|
+
#
|
114
|
+
# Throws CommandFailedError
|
115
|
+
|
116
|
+
def list(keyword=nil, pattern=nil)
|
117
|
+
cmd = ['list', keyword, pattern].join ' '
|
118
|
+
send_cmd(cmd)
|
119
|
+
list = read_response()
|
120
|
+
responsecode = list[0][0..2]
|
121
|
+
case responsecode
|
122
|
+
when '215'
|
123
|
+
case keyword
|
124
|
+
when /overview.fmt/
|
125
|
+
@overview_format_raw = list
|
126
|
+
@overview_format = Net::NNTP.parse_overview_format list.join
|
127
|
+
else
|
128
|
+
create_grouplist(list)
|
129
|
+
end
|
130
|
+
|
131
|
+
when '501', '503', '500'
|
132
|
+
raise CommandFailedError, list
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# prepares overview format as read from server, used by Net::NNTP::Article and list()
|
137
|
+
def self.parse_overview_format(format)
|
138
|
+
overview_format = %w{id}
|
139
|
+
format.split(/\r?\n/).each do |line|
|
140
|
+
next if line[0] == ?2 || line[0] == ?.
|
141
|
+
ident = line.scan(/\w/).join.downcase
|
142
|
+
unless ident[0..3] == 'xref'
|
143
|
+
overview_format << ident
|
144
|
+
else
|
145
|
+
overview_format << 'xref'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
overview_format
|
149
|
+
end
|
150
|
+
|
151
|
+
# TODO: complete implementation
|
152
|
+
def stat
|
153
|
+
end
|
154
|
+
|
155
|
+
# Issues 'HEAD' command to NNTP server, returning raw response
|
156
|
+
#
|
157
|
+
# Throws CommandFailedError
|
158
|
+
def head(args=nil)
|
159
|
+
suffix = numbers_or_id(args)
|
160
|
+
cmd = 'head'
|
161
|
+
cmd = ['head', suffix].join " " if suffix
|
162
|
+
send_cmd(cmd)
|
163
|
+
response = read_response()
|
164
|
+
case response[0][0..2]
|
165
|
+
when '221'
|
166
|
+
return response
|
167
|
+
else
|
168
|
+
raise CommandFailedError, response
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Issues 'BODY' command to NNTP server, returning raw response.
|
173
|
+
# options:: messageid|id
|
174
|
+
#
|
175
|
+
# Throws CommandFailedError
|
176
|
+
def body(args=nil)
|
177
|
+
suffix = args
|
178
|
+
cmd = 'body'
|
179
|
+
cmd = ['body', suffix].join " " if suffix
|
180
|
+
send_cmd(cmd)
|
181
|
+
response = read_response()
|
182
|
+
case response[0][0..2]
|
183
|
+
when '222'
|
184
|
+
return response
|
185
|
+
else
|
186
|
+
raise CommandFailedError, response
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# Issues 'ARTICLE' command to NNTP server, returning raw response.
|
191
|
+
# options:: messageid|id
|
192
|
+
#
|
193
|
+
# Throws CommandFailedError
|
194
|
+
def article(args=nil)
|
195
|
+
suffix = args
|
196
|
+
cmd = 'article'
|
197
|
+
cmd = ['article', suffix].join " " if suffix
|
198
|
+
send_cmd(cmd)
|
199
|
+
response = read_response()
|
200
|
+
case response[0][0..2]
|
201
|
+
when '220'
|
202
|
+
return response
|
203
|
+
else
|
204
|
+
raise CommandFailedError, response
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def last_or_next(cmd)
|
209
|
+
raise ProtocolError, "No group selected" unless @group
|
210
|
+
send_cmd(cmd)
|
211
|
+
response = read_response()[0]
|
212
|
+
code = response[0..2]
|
213
|
+
article = @group.articles.create
|
214
|
+
case code
|
215
|
+
when '223'
|
216
|
+
code, id, msgid, what = response.split
|
217
|
+
article.id = id
|
218
|
+
article.messageid = msgid
|
219
|
+
else
|
220
|
+
raise CommandFailedError, response
|
221
|
+
end
|
222
|
+
response
|
223
|
+
end
|
224
|
+
|
225
|
+
# Issues the LAST command to the NNTP server, returning the raw response
|
226
|
+
def last
|
227
|
+
last_or_next("last")
|
228
|
+
end
|
229
|
+
|
230
|
+
def next
|
231
|
+
last_or_next("next")
|
232
|
+
end
|
233
|
+
|
234
|
+
def create_grouplist(response)
|
235
|
+
@grouplist = {}
|
236
|
+
response.each do |line|
|
237
|
+
next if line[0..2] == '215'
|
238
|
+
break if line =~ /^\.\r\n$/
|
239
|
+
groupinfo = line.split
|
240
|
+
group = Group.new groupinfo.shift
|
241
|
+
group.article_info = groupinfo
|
242
|
+
@grouplist[group.name] = group
|
243
|
+
end
|
244
|
+
@grouplist
|
245
|
+
end
|
246
|
+
|
247
|
+
def send_cmd(cmd)
|
248
|
+
@socket.write(cmd+"\r\n")
|
249
|
+
end
|
250
|
+
|
251
|
+
def read_response
|
252
|
+
response = ''
|
253
|
+
queue = Queue.new
|
254
|
+
str = ''
|
255
|
+
ra = []
|
256
|
+
loop do
|
257
|
+
str = @socket.readline
|
258
|
+
queue << str
|
259
|
+
ra << str
|
260
|
+
break if str == ".\r\n" || !str
|
261
|
+
end
|
262
|
+
ra
|
263
|
+
end
|
264
|
+
|
265
|
+
def numbers_or_id(hash)
|
266
|
+
return nil unless hash
|
267
|
+
suffix = ''
|
268
|
+
from = hash[:from]
|
269
|
+
to = hash[:to]
|
270
|
+
msgid = hash[:message_id]
|
271
|
+
if from
|
272
|
+
suffix = "#{from}-"
|
273
|
+
suffix += "#{to}" if to
|
274
|
+
elsif msgid
|
275
|
+
suffix = "#{msgid}"
|
276
|
+
end
|
277
|
+
suffix
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
private :read_response, :numbers_or_id, :send_cmd, :last_or_next, :create_grouplist
|
282
|
+
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
# vim:sts=2:ts=2:sw=2:sta:noet
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Net
|
2
|
+
class NNTP
|
3
|
+
class Article
|
4
|
+
attr_accessor :id, :messageid, :subject, :group
|
5
|
+
attr_reader :overview_format, :bytes, :lines, :xref, :date
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@overview_format = %w{id}
|
9
|
+
end
|
10
|
+
|
11
|
+
def overview_format=(format)
|
12
|
+
@overview_format = Net::NNTP.parse_overview_format format
|
13
|
+
end
|
14
|
+
|
15
|
+
def overview(over)
|
16
|
+
over.split(/\t/).each_with_index do |value, index|
|
17
|
+
ident = @overview_format[index]
|
18
|
+
eval "@#{ident} = value;"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Net
|
2
|
+
|
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
|
+
"Group: #{@name} #{@article_count} #{@article_first} #{@article_last}"
|
38
|
+
end
|
39
|
+
|
40
|
+
class Articles
|
41
|
+
|
42
|
+
attr_accessor :group
|
43
|
+
|
44
|
+
def initialize(group)
|
45
|
+
@articles ||=[]
|
46
|
+
end
|
47
|
+
|
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
|
+
|
55
|
+
def length
|
56
|
+
@articles.length
|
57
|
+
end
|
58
|
+
|
59
|
+
def <<(article)
|
60
|
+
@articles << article
|
61
|
+
end
|
62
|
+
|
63
|
+
def create
|
64
|
+
a = Article.new
|
65
|
+
a.group = self.group
|
66
|
+
@articles << a
|
67
|
+
a
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'net/nntp.rb'
|
4
|
+
require 'mock/mock_socket'
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
module TestNet
|
9
|
+
class TestNNTP < Test::Unit::TestCase
|
10
|
+
|
11
|
+
def setup
|
12
|
+
nntp_connect_and_auth('localhost', 119, 'dummy', 'test')
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_new
|
16
|
+
host = 'localhost'
|
17
|
+
port = '119'
|
18
|
+
assert_nothing_raised do
|
19
|
+
@nntp = Net::NNTP.new(host)
|
20
|
+
end
|
21
|
+
assert_nothing_raised do
|
22
|
+
nntp_new(host, port)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_connect
|
27
|
+
assert_nothing_raised do
|
28
|
+
@nntp.connect
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_help
|
33
|
+
help = @nntp.help.join
|
34
|
+
assert_equal '100', help[0..2]
|
35
|
+
assert_equal 39, help.length
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_authenticate
|
39
|
+
assert_nothing_raised do
|
40
|
+
assert nntp_connect_and_auth('localhost', 119, 'dummy', 'test')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_group
|
45
|
+
assert_nothing_raised do
|
46
|
+
group = @nntp.group('at.linux')
|
47
|
+
assert_kind_of Net::NNTP::Group, group
|
48
|
+
assert_equal 'at.linux', group.name
|
49
|
+
assert_equal 12, group.article_count
|
50
|
+
assert_equal 1363, group.article_first
|
51
|
+
assert_equal 1375, group.article_last
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_xhdr
|
56
|
+
headers = @nntp.xhdr('at.linux', 'subject', :from => 1363, :to => 1375)
|
57
|
+
assert_equal 15, headers.length
|
58
|
+
assert_equal '221', headers[0][0..2]
|
59
|
+
assert_equal "1364", headers[2].split[0]
|
60
|
+
header = @nntp.xhdr('at.linux', 'subject', :message_id => "<slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>").join
|
61
|
+
assert_equal 49, header.length
|
62
|
+
assert_equal "1375", header.split[0]
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_xhdr_fails
|
66
|
+
header = @nntp.xhdr('at.linux', '', {}).join
|
67
|
+
assert_equal '502', header[0..2]
|
68
|
+
assert_raise(Net::NNTP::CommandFailedError) do
|
69
|
+
header = @nntp.xhdr('at.xxx', 'subject', {})
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def test_group_fails
|
75
|
+
assert_raise(Net::NNTP::CommandFailedError) do
|
76
|
+
group = @nntp.group('at.xxx')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_xover
|
81
|
+
overviews = @nntp.xover('at.linux', :from => 1363, :to => 1375)
|
82
|
+
assert_equal 15, overviews.length
|
83
|
+
assert_equal '224', overviews[0][0..2]
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_xover_fails
|
87
|
+
over = @nntp.xover('at.linux', :from => 1363, :to => 1375)
|
88
|
+
over = @nntp.xover('at.linux', :message_id => "<slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>").join
|
89
|
+
assert_equal '502', over[0..2]
|
90
|
+
assert_raises(Net::NNTP::CommandFailedError) do
|
91
|
+
over = @nntp.xover('at.xxx', :message_id => "<slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_listgroup
|
96
|
+
list = @nntp.listgroup('at.linux')
|
97
|
+
assert_equal 15, list.length
|
98
|
+
match = /(\d{3}).*for\s+(\S+)\s/.match(list[0])
|
99
|
+
assert_equal "211", match[1]
|
100
|
+
assert_equal "at.linux", match[2]
|
101
|
+
assert_equal "1365\r\n", list[3]
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_list
|
105
|
+
assert_respond_to @nntp, :list
|
106
|
+
assert_nothing_raised do
|
107
|
+
@nntp.list('overview.fmt')
|
108
|
+
assert_equal 9, @nntp.overview_format.length
|
109
|
+
@nntp.list()
|
110
|
+
assert_not_equal 0, @nntp.grouplist.length
|
111
|
+
assert_not_nil @nntp.grouplist
|
112
|
+
assert_equal 'at.test', @nntp.grouplist['at.test'].name
|
113
|
+
@nntp.list('active')
|
114
|
+
assert_equal 'at.test', @nntp.grouplist['at.test'].name
|
115
|
+
@nntp.list('active.times')
|
116
|
+
@nntp.list('active.times', 'at.*')
|
117
|
+
end
|
118
|
+
assert_raise Net::NNTP::CommandFailedError do
|
119
|
+
@nntp.list('distrib.pat', 'at.*')
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_article
|
124
|
+
assert_raises Net::NNTP::CommandFailedError do
|
125
|
+
article = @nntp.article
|
126
|
+
end
|
127
|
+
article = @nntp.article("<5d6be$4625ae23$51df8a12$32566@news.inode.at>")
|
128
|
+
response, id, msgid = article[0].split
|
129
|
+
assert_equal '220', response
|
130
|
+
assert_equal '1392', id
|
131
|
+
assert_equal "<5d6be$4625ae23$51df8a12$32566@news.inode.at>", msgid
|
132
|
+
group = @nntp.group 'at.linux'
|
133
|
+
article = @nntp.article '1392'
|
134
|
+
response, id, msgid = article[0].split
|
135
|
+
assert_equal '220', response
|
136
|
+
assert_equal '1392', id
|
137
|
+
assert_equal "<5d6be$4625ae23$51df8a12$32566@news.inode.at>", msgid
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_head
|
141
|
+
nntp_connect_and_auth('localhost', 119, 'dummy', 'test')
|
142
|
+
assert_nothing_raised do
|
143
|
+
assert_respond_to @nntp, :head
|
144
|
+
end
|
145
|
+
assert_raise Net::NNTP::CommandFailedError do
|
146
|
+
head = @nntp.head
|
147
|
+
end
|
148
|
+
@nntp.group 'at.linux'
|
149
|
+
@io = [
|
150
|
+
"221 1430 <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net> article retrieved - head follows\r\n",
|
151
|
+
"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",
|
152
|
+
"Message-ID: <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net>\r\n",
|
153
|
+
"From: Gerhard Engler <gerhard.engler@gmx.de>\r\n",
|
154
|
+
"Newsgroups: at.linux\r\n",
|
155
|
+
"Subject: Re: udev_node_mknod: /dev/capi Operation not permitted\r\n",
|
156
|
+
"Date: Tue, 24 Apr 2007 14:39:11 +0200\r\n",
|
157
|
+
"References: <4629ee10$0$10187$9b4e6d93@newsspool4.arcor-online.net> <slrnf2np7k.a8e.tom-usenet@eristoteles.iwoars.net>\r\n",
|
158
|
+
"Lines: 26\r\n",
|
159
|
+
"User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)\r\n",
|
160
|
+
"MIME-Version: 1.0\r\n",
|
161
|
+
"In-Reply-To: <slrnf2np7k.a8e.tom-usenet@eristoteles.iwoars.net>\r\n",
|
162
|
+
"Content-Type: text/plain; charset=ISO-8859-15; format=flowed\r\n",
|
163
|
+
"Content-Transfer-Encoding: 7bit\r\n",
|
164
|
+
"Organization: Arcor\r\n",
|
165
|
+
"NNTP-Posting-Date: 24 Apr 2007 14:39:11 CEST\r\n",
|
166
|
+
"NNTP-Posting-Host: 6cf11d8c.newsspool1.arcor-online.net\r\n",
|
167
|
+
"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",
|
168
|
+
"X-Complaints-To: usenet-abuse@arcor.de\r\n",
|
169
|
+
"Xref: sensor.twincode.net at.linux:1430\r\n",
|
170
|
+
".\r\n"
|
171
|
+
]
|
172
|
+
head = @nntp.head
|
173
|
+
assert_kind_of Array, head
|
174
|
+
response, id, msgid = head[0].split
|
175
|
+
assert_equal '221', response
|
176
|
+
assert_equal '1430', id
|
177
|
+
assert_equal '<462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net>', msgid
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_body
|
181
|
+
assert_raises Net::NNTP::CommandFailedError do
|
182
|
+
body = @nntp.body
|
183
|
+
end
|
184
|
+
body = @nntp.body("<5d6be$4625ae23$51df8a12$32566@news.inode.at>")
|
185
|
+
response, id, msgid = body[0].split
|
186
|
+
assert_equal '222', response
|
187
|
+
assert_equal '1392', id
|
188
|
+
assert_equal "<5d6be$4625ae23$51df8a12$32566@news.inode.at>", msgid
|
189
|
+
group = @nntp.group 'at.linux'
|
190
|
+
body = @nntp.body '1392'
|
191
|
+
response, id, msgid = body[0].split
|
192
|
+
assert_equal '222', response
|
193
|
+
assert_equal '1392', id
|
194
|
+
assert_equal "<5d6be$4625ae23$51df8a12$32566@news.inode.at>", msgid
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_stat
|
198
|
+
assert_nothing_raised do
|
199
|
+
assert_respond_to @nntp, :stat
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_last
|
204
|
+
assert_raise Net::NNTP::ProtocolError do
|
205
|
+
last = @nntp.last
|
206
|
+
end
|
207
|
+
@nntp.group 'at.linux'
|
208
|
+
assert_raise Net::NNTP::CommandFailedError do
|
209
|
+
last = @nntp.last
|
210
|
+
end
|
211
|
+
@nntp.next
|
212
|
+
@nntp.next
|
213
|
+
last = @nntp.last
|
214
|
+
assert_kind_of String, last
|
215
|
+
response, article, msgid, rest = last.split
|
216
|
+
assert_equal "223", response
|
217
|
+
assert_equal "1363", article
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_next
|
221
|
+
assert_raise Net::NNTP::ProtocolError do
|
222
|
+
anext = @nntp.next
|
223
|
+
end
|
224
|
+
@nntp.group 'at.linux'
|
225
|
+
anext = @nntp.next
|
226
|
+
assert_kind_of String, anext
|
227
|
+
response, article, msgid, rest = anext.split
|
228
|
+
assert_equal "223", response
|
229
|
+
assert_equal "1363", article
|
230
|
+
assert_equal "<example.msgid@fake.host>", msgid
|
231
|
+
anext = @nntp.next
|
232
|
+
response, article, msgid, rest = anext.split
|
233
|
+
assert_equal "1364", article
|
234
|
+
end
|
235
|
+
|
236
|
+
private
|
237
|
+
def nntp_new(host, port=119)
|
238
|
+
@nntp = Net::NNTP.new(host, port)
|
239
|
+
end
|
240
|
+
def nntp_connect_and_auth(host, port, user, pass)
|
241
|
+
@nntp = Net::NNTP.new(host, port)
|
242
|
+
@nntp.instance_variable_set :@socket_class, MockSocket
|
243
|
+
@nntp.connect
|
244
|
+
@nntp.socket.activate
|
245
|
+
@nntp.authenticate(user, pass)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
@@ -0,0 +1,330 @@
|
|
1
|
+
require 'mock'
|
2
|
+
class MockSocket < Test::Unit::MockObject( TCPSocket )
|
3
|
+
def initialize(host, port)
|
4
|
+
super
|
5
|
+
@io = ["200 Welcome\r\n"]
|
6
|
+
@authenticated = false
|
7
|
+
@group_selected = nil
|
8
|
+
@last_article = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def alive?
|
12
|
+
super
|
13
|
+
true
|
14
|
+
end
|
15
|
+
|
16
|
+
def recv(len)
|
17
|
+
return readline
|
18
|
+
end
|
19
|
+
|
20
|
+
def read( len )
|
21
|
+
super # Call the mocked method to record the call
|
22
|
+
rval = @io[0,len]
|
23
|
+
@io[0,len] = ''
|
24
|
+
return %w{ you should never reach this }
|
25
|
+
end
|
26
|
+
|
27
|
+
def puts(stuff)
|
28
|
+
super
|
29
|
+
stuff += "\r\n"
|
30
|
+
write stuff
|
31
|
+
end
|
32
|
+
|
33
|
+
def write( str )
|
34
|
+
super # Call the mocked method to record the call
|
35
|
+
@io = []
|
36
|
+
case str.downcase
|
37
|
+
when /^body(.*)/
|
38
|
+
body = [
|
39
|
+
"222 1392 <5d6be$4625ae23$51df8a12$32566@news.inode.at> article retrieved - body follows\r\n",
|
40
|
+
"Hi,\r\n",
|
41
|
+
"\r\n",
|
42
|
+
"kennt ihr eine Moeglichkeit den maximalen Speicherbedarf eines Programms \r\n",
|
43
|
+
"ueber dessen gesamte Laufzeit zu ermitteln? Also keine Momentaufnahme \r\n",
|
44
|
+
"wie mit ps, top & Co?\r\n",
|
45
|
+
"\r\n",
|
46
|
+
"Danke & vG\r\n",
|
47
|
+
"Franz Hollerer\r\n",
|
48
|
+
".\r\n"
|
49
|
+
]
|
50
|
+
case $1
|
51
|
+
when /^\s+1392/, /^\s*$/
|
52
|
+
if @group_selected
|
53
|
+
@io = body
|
54
|
+
else
|
55
|
+
@io = ["412 No Group selected"]
|
56
|
+
end
|
57
|
+
when /^\s*<5d6be\$4625ae23\$51df8a12\$32566@news\.inode\.at>/
|
58
|
+
@io = body
|
59
|
+
else
|
60
|
+
@io = ["No such article"]
|
61
|
+
end
|
62
|
+
when /^article(.*)/
|
63
|
+
article = [
|
64
|
+
"220 1392 <5d6be$4625ae23$51df8a12$32566@news.inode.at> article retrieved - text follows\r\n",
|
65
|
+
"Path: vietwist00.chello.at!newsfeed02.chello.at!news.inode.at.POSTED!not-for-mail\r\n",
|
66
|
+
"Message-ID: <5d6be$4625ae23$51df8a12$32566@news.inode.at>\r\n",
|
67
|
+
"From: Franz Hollerer <franz.hollerer@ims.co.at>\r\n",
|
68
|
+
"Newsgroups: at.linux\r\n",
|
69
|
+
"Subject: Q: maximalen Speicherbedarfs eines Programms ueber dessen gesamte\r\n",
|
70
|
+
" Laufzeit\r\n",
|
71
|
+
"Date: Wed, 18 Apr 2007 07:34:56 +0200\r\n",
|
72
|
+
"Lines: 8\r\n",
|
73
|
+
"User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)\r\n",
|
74
|
+
"MIME-Version: 1.0\r\n",
|
75
|
+
"Content-Type: text/plain; charset=ISO-8859-15; format=flowed\r\n",
|
76
|
+
"Content-Transfer-Encoding: 7bit\r\n",
|
77
|
+
"X-Complaints-To: abuse@inode.at\r\n",
|
78
|
+
"NNTP-Posting-Host: 81.223.138.18 (81.223.138.18)\r\n",
|
79
|
+
"NNTP-Posting-Date: Wed, 18 Apr 2007 07:35:31 +0200\r\n",
|
80
|
+
"X-Trace: 5d6be4625ae23f47a2fb732566\r\n",
|
81
|
+
"Xref: sensor.twincode.net at.linux:1392\r\n",
|
82
|
+
"\r\n",
|
83
|
+
"Hi,\r\n",
|
84
|
+
"\r\n",
|
85
|
+
"kennt ihr eine Moeglichkeit den maximalen Speicherbedarf eines Programms \r\n",
|
86
|
+
"ueber dessen gesamte Laufzeit zu ermitteln? Also keine Momentaufnahme \r\n",
|
87
|
+
"wie mit ps, top & Co?\r\n",
|
88
|
+
"\r\n",
|
89
|
+
"Danke & vG\r\n",
|
90
|
+
"Franz Hollerer\r\n",
|
91
|
+
".\r\n"
|
92
|
+
]
|
93
|
+
case $1
|
94
|
+
when /\s*1392/
|
95
|
+
if @group_selected
|
96
|
+
@io = article
|
97
|
+
else
|
98
|
+
@io = ["412 No Group selected"]
|
99
|
+
end
|
100
|
+
when /^\s*<5d6be\$4625ae23\$51df8a12\$32566@news\.inode\.at>/
|
101
|
+
@io = article
|
102
|
+
else
|
103
|
+
@io = ["430 No such article"]
|
104
|
+
end
|
105
|
+
when /^list\b\s*(.*)\r\n$/
|
106
|
+
case $1
|
107
|
+
when /overview.fmt/i
|
108
|
+
@io = ["215 Order of fields in overview database.\r\nSubject:\r\nFrom:\r\nDate:\r\nMessage-ID:\r\nReferences:\r\nBytes:\r\nLines:\r\nXref:full\r\n.\r\n" ]
|
109
|
+
when /active\s*(.*)/
|
110
|
+
@io = ["215 Newsgroups in form \"group high low flags\".", "at.test 200 100 y\r\n", "at.linux 100 90 n\r\n", ".\r\n"]
|
111
|
+
when /^\s*$/
|
112
|
+
@io = ["215 Newsgroups in form \"group high low flags\".", "at.test 200 100 y\r\n", "at.linux 100 90 n\r\n", ".\r\n"]
|
113
|
+
else
|
114
|
+
@io = ["501 Bad Command Usage"]
|
115
|
+
end
|
116
|
+
when "help\r\n" then
|
117
|
+
@io = ["100 Legal commands on THIS server:\r\n", ".\r\n"]
|
118
|
+
when /^next/i
|
119
|
+
if @group_selected
|
120
|
+
if @last_article
|
121
|
+
if @last_article < 1375
|
122
|
+
@last_article += 1
|
123
|
+
else
|
124
|
+
@last_article = nil
|
125
|
+
end
|
126
|
+
else
|
127
|
+
@last_article = 1363
|
128
|
+
end
|
129
|
+
@io = @last_article ? ["223 #{@last_article} <example.msgid@fake.host> retrieved"] : ['421 No next article in group']
|
130
|
+
else
|
131
|
+
@io = ['412 No Group selected']
|
132
|
+
end
|
133
|
+
when /^last/i
|
134
|
+
if @group_selected
|
135
|
+
if @last_article
|
136
|
+
if @last_article > 1363
|
137
|
+
@last_article -= 1
|
138
|
+
else
|
139
|
+
@last_article = nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
@io = @last_article ? ["223 #{@last_article} <example.msgid@fake.host> retrieved"] : ['421 No next article in group']
|
143
|
+
else
|
144
|
+
@io = ['412 No Group selected']
|
145
|
+
end
|
146
|
+
when /^mode reader/i
|
147
|
+
@io = ["200 Welcome"]
|
148
|
+
when /^listgroup\s*(.*)\s*/i
|
149
|
+
case $1
|
150
|
+
when 'at.linux'
|
151
|
+
@io = [
|
152
|
+
"211 Article list for at.linux follows\r\n",
|
153
|
+
"1363\r\n",
|
154
|
+
"1364\r\n",
|
155
|
+
"1365\r\n",
|
156
|
+
"1366\r\n",
|
157
|
+
"1367\r\n",
|
158
|
+
"1368\r\n",
|
159
|
+
"1369\r\n",
|
160
|
+
"1370\r\n",
|
161
|
+
"1371\r\n",
|
162
|
+
"1372\r\n",
|
163
|
+
"1373\r\n",
|
164
|
+
"1374\r\n",
|
165
|
+
"1375\r\n",
|
166
|
+
".\r\n"
|
167
|
+
]
|
168
|
+
else
|
169
|
+
if @group_selected
|
170
|
+
@io = [
|
171
|
+
"211 Article list for at.linux follows\r\n",
|
172
|
+
"1363\r\n",
|
173
|
+
"1364\r\n",
|
174
|
+
"1365\r\n",
|
175
|
+
"1366\r\n",
|
176
|
+
"1367\r\n",
|
177
|
+
"1368\r\n",
|
178
|
+
"1369\r\n",
|
179
|
+
"1370\r\n",
|
180
|
+
"1371\r\n",
|
181
|
+
"1372\r\n",
|
182
|
+
"1373\r\n",
|
183
|
+
"1374\r\n",
|
184
|
+
"1375\r\n",
|
185
|
+
".\r\n"
|
186
|
+
]
|
187
|
+
else
|
188
|
+
@io = ['412 No Group selected']
|
189
|
+
end
|
190
|
+
end
|
191
|
+
when "quit\r\n" then
|
192
|
+
@io = ["200 Good bye"]
|
193
|
+
when "authinfo user dummy\r\n"
|
194
|
+
@io = ["381 More authentication details needed"]
|
195
|
+
when "authinfo pass test\r\n"
|
196
|
+
@io = ["281 Welcome to dummytest"]
|
197
|
+
when /^group\s+(.+)\s*\r\n$/
|
198
|
+
case $1
|
199
|
+
when 'at.linux'
|
200
|
+
@io = ["211 12 1363 1375 at.linux"]
|
201
|
+
@group_selected = 'at.linux'
|
202
|
+
else
|
203
|
+
@io = ["411 No such group"]
|
204
|
+
end
|
205
|
+
when "xhdr subject <slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>\r\n"
|
206
|
+
@io =
|
207
|
+
["1375 Re: Bitte um Meinungen ==> Virtualisierung\r\n"]
|
208
|
+
when "xhdr subject 1363-1375\r\n"
|
209
|
+
if @group_selected
|
210
|
+
@io = [
|
211
|
+
"221 Subject header (from overview) for postings 1363-1375\r\n",
|
212
|
+
"1363 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
213
|
+
"1364 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
214
|
+
"1365 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
215
|
+
"1366 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
216
|
+
"1367 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
217
|
+
"1368 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
218
|
+
"1369 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
219
|
+
"1370 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
220
|
+
"1371 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
221
|
+
"1372 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
222
|
+
"1373 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
223
|
+
"1374 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
224
|
+
"1375 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
225
|
+
".\r\n"
|
226
|
+
]
|
227
|
+
else
|
228
|
+
@io = ['412 No group selected']
|
229
|
+
end
|
230
|
+
when "xover 1363-1375\r\n"
|
231
|
+
if @group_selected
|
232
|
+
@io = [
|
233
|
+
"224 Overview information for postings 1363-1375:\r\n",
|
234
|
+
"1363 Re: Bitte um Meinungen ==> Virtualisierung \"Igo Besser\" <i.besser@aon.at> Sun, 15 Apr 2007 14:09:46 +0200 <46221541$0$2299$91cee783@newsreader01.highway.telekom.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <evt242$1jc7$1@geiz-ist-geil.priv.at> 1165 9 Xref: sensor.twincode.net at.linux:1363\r\n",
|
235
|
+
"1364 Re: Bitte um Meinungen ==> Virtualisierung \"Igo Besser\" <i.besser@aon.at> Sun, 15 Apr 2007 14:14:12 +0200 <4622164b$0$25611$91cee783@newsreader02.highway.telekom.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <4621fc17$0$2315$91cee783@newsreader01.highway.telekom.at> <evt1p1$1jar$1@geiz-ist-geil.priv.at> 1229 13 Xref: sensor.twincode.net at.linux:1364\r\n",
|
236
|
+
"1365 Re: Bitte um Meinungen ==> Virtualisierung \"Peter J. Holzer\" <hjp-usenet2@hjp.at> Sun, 15 Apr 2007 16:39:56 +0200 <slrnf24e9s.dtb.hjp-usenet2@zeno.hjp.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> 2643 42 Xref: sensor.twincode.net at.linux:1365\r\n",
|
237
|
+
"1366 Re: Bitte um Meinungen ==> Virtualisierung \"Igo Besser\" <i.besser@aon.at> Sun, 15 Apr 2007 19:14:08 +0200 <46225c97$0$25626$91cee783@newsreader02.highway.telekom.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <slrnf24e9s.dtb.hjp-usenet2@zeno.hjp.at> 1344 13 Xref: sensor.twincode.net at.linux:1366\r\n",
|
238
|
+
"1367 Re: Bitte um Meinungen ==> Virtualisierung \"Peter J. Holzer\" <hjp-usenet2@hjp.at> Sun, 15 Apr 2007 21:35:27 +0200 <slrnf24vjv.7pk.hjp-usenet2@zeno.hjp.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <slrnf24e9s.dtb.hjp-usenet2@zeno.hjp.at> <46225c97$0$25626$91cee783@newsreader02.highway.telekom.at> 1851 24 Xref: sensor.twincode.net at.linux:1367\r\n",
|
239
|
+
"1368 Re: Bitte um Meinungen ==> Virtualisierung Wolfgang Steger <wolfgangs-spambox@utanet.at> Sun, 15 Apr 2007 21:48:48 +0200 <16caf4-581.ln1@swws1.dyndns.org> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <slrnf24e9s.dtb.hjp-usenet2@zeno.hjp.at> <46225c97$0$25626$91cee783@newsreader02.highway.telekom.at> 2248 20 Xref: sensor.twincode.net at.linux:1368\r\n",
|
240
|
+
"1369 Re: Bitte um Meinungen ==> Virtualisierung Michael Prokop <devnull@michael-prokop.at> Sun, 15 Apr 2007 22:22:46 +0200 <2007-04-15T22-19-44@devnull.michael-prokop.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <slrnf24e9s.dtb.hjp-usenet2@zeno.hjp.at> <46225c97$0$25626$91cee783@newsreader02.highway.telekom.at> <slrnf24vjv.7pk.hjp-usenet2@zeno.hjp.at> 2022 23 Xref: sensor.twincode.net at.linux:1369\r\n",
|
241
|
+
"1370 Re: Bitte um Meinungen ==> Virtualisierung Robert Annessi <robert@annessi.at> Sun, 15 Apr 2007 22:52:36 +0200 <46229089$0$10578$3b214f66@tunews.univie.ac.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <slrnf24e9s.dtb.hjp-usenet2@zeno.hjp.at> <46225c97$0$25626$91cee783@newsreader02.highway.telekom.at> <16caf4-581.ln1@swws1.dyndns.org> 1807 27 Xref: sensor.twincode.net at.linux:1370\r\n",
|
242
|
+
"1371 Re: Bitte um Meinungen ==> Virtualisierung \"Thomas Spachinger\" <t.spachinger@gmx.at> Sun, 15 Apr 2007 22:58:17 +0200 <58fi18F2gdp4eU1@mid.individual.net> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <4621fc17$0$2315$91cee783@newsreader01.highway.telekom.at> <evt1p1$1jar$1@geiz-ist-geil.priv.at> <4622164b$0$25611$91cee783@newsreader02.highway.telekom.at> 1427 18 Xref: sensor.twincode.net at.linux:1371\r\n",
|
243
|
+
"1372 Re: Bitte um Meinungen ==> Virtualisierung Bernd Haug <haug@berndhaug.net> Sun, 15 Apr 2007 23:54:05 +0200 <tgjaf4-lt9.ln1@this.is.a.news.server.you.goddamn.stupid.program> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <slrnf24e9s.dtb.hjp-usenet2@zeno.hjp.at> <46225c97$0$25626$91cee783@newsreader02.highway.telekom.at> <slrnf24vjv.7pk.hjp-usenet2@zeno.hjp.at> 1721 10 Xref: sensor.twincode.net at.linux:1372\r\n",
|
244
|
+
"1373 Re: Bitte um Meinungen ==> Virtualisierung Wolfgang Fuschlberger <usenet-2006-05@fuschlberger.net> Sun, 15 Apr 2007 23:58:07 +0200 <fojaf4-kcj.ln1@window.dtdns.net> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <slrnf24e9s.dtb.hjp-usenet2@zeno.hjp.at> <46225c97$0$25626$91cee783@newsreader02.highway.telekom.at> <16caf4-581.ln1@swws1.dyndns.org> <46229089$0$10578$3b214f66@tunews.univie.ac.at> 1800 17 Xref: sensor.twincode.net at.linux:1373\r\n",
|
245
|
+
"1374 Re: Bitte um Meinungen ==> Virtualisierung Andreas Labres <al-nospam0310&bounce@labres.at> Mon, 16 Apr 2007 08:57:43 +0200 <1tnru1ccirb05.dlg@al.lab.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> 1702 19 Xref: sensor.twincode.net at.linux:1374\r\n",
|
246
|
+
"1375 Re: Bitte um Meinungen ==> Virtualisierung \"Peter J. Holzer\" <hjp-usenet2@hjp.at> Mon, 16 Apr 2007 09:49:46 +0200 <slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at> <4621dbb8$0$2310$91cee783@newsreader01.highway.telekom.at> <dh49f4-qem.ln1@this.is.a.news.server.you.goddamn.stupid.program> <slrnf23snh.dfm.hjp-usenet2@zeno.hjp.at> <4621ff58$0$2307$91cee783@newsreader01.highway.telekom.at> <1tnru1ccirb05.dlg@al.lab.at> 2127 33 Xref: sensor.twincode.net at.linux:1375\r\n",
|
247
|
+
".\r\n"
|
248
|
+
]
|
249
|
+
else
|
250
|
+
@io = ["412 No Group selected"]
|
251
|
+
end
|
252
|
+
when /xover \<.+\>/
|
253
|
+
@io = ["502 Usage: OVER first[-[last]]"]
|
254
|
+
when /^xhdr\s*$/
|
255
|
+
@io = ["502 Usage: HDR header [first[-last]]|[message-id]"]
|
256
|
+
when /^head(.*)$/
|
257
|
+
case $1
|
258
|
+
when /^\s+(1430|<462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net>)/
|
259
|
+
@io = [
|
260
|
+
"221 1430 <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net> article retrieved - head follows\r\n",
|
261
|
+
"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",
|
262
|
+
"Message-ID: <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net>\r\n",
|
263
|
+
"From: Gerhard Engler <gerhard.engler@gmx.de>\r\n",
|
264
|
+
"Newsgroups: at.linux\r\n",
|
265
|
+
"Subject: Re: udev_node_mknod: /dev/capi Operation not permitted\r\n",
|
266
|
+
"Date: Tue, 24 Apr 2007 14:39:11 +0200\r\n",
|
267
|
+
"References: <4629ee10$0$10187$9b4e6d93@newsspool4.arcor-online.net> <slrnf2np7k.a8e.tom-usenet@eristoteles.iwoars.net>\r\n",
|
268
|
+
"Lines: 26\r\n",
|
269
|
+
"User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)\r\n",
|
270
|
+
"MIME-Version: 1.0\r\n",
|
271
|
+
"In-Reply-To: <slrnf2np7k.a8e.tom-usenet@eristoteles.iwoars.net>\r\n",
|
272
|
+
"Content-Type: text/plain; charset=ISO-8859-15; format=flowed\r\n",
|
273
|
+
"Content-Transfer-Encoding: 7bit\r\n",
|
274
|
+
"Organization: Arcor\r\n",
|
275
|
+
"NNTP-Posting-Date: 24 Apr 2007 14:39:11 CEST\r\n",
|
276
|
+
"NNTP-Posting-Host: 6cf11d8c.newsspool1.arcor-online.net\r\n",
|
277
|
+
"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",
|
278
|
+
"X-Complaints-To: usenet-abuse@arcor.de\r\n",
|
279
|
+
"Xref: sensor.twincode.net at.linux:1430\r\n",
|
280
|
+
".\r\n"
|
281
|
+
]
|
282
|
+
|
283
|
+
when /^\s?$/
|
284
|
+
if @group_selected
|
285
|
+
@io = [
|
286
|
+
"221 1430 <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net> article retrieved - head follows\r\n",
|
287
|
+
"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",
|
288
|
+
"Message-ID: <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net>\r\n",
|
289
|
+
"From: Gerhard Engler <gerhard.engler@gmx.de>\r\n",
|
290
|
+
"Newsgroups: at.linux\r\n",
|
291
|
+
"Subject: Re: udev_node_mknod: /dev/capi Operation not permitted\r\n",
|
292
|
+
"Date: Tue, 24 Apr 2007 14:39:11 +0200\r\n",
|
293
|
+
"References: <4629ee10$0$10187$9b4e6d93@newsspool4.arcor-online.net> <slrnf2np7k.a8e.tom-usenet@eristoteles.iwoars.net>\r\n",
|
294
|
+
"Lines: 26\r\n",
|
295
|
+
"User-Agent: Thunderbird 1.5.0.10 (Windows/20070221)\r\n",
|
296
|
+
"MIME-Version: 1.0\r\n",
|
297
|
+
"In-Reply-To: <slrnf2np7k.a8e.tom-usenet@eristoteles.iwoars.net>\r\n",
|
298
|
+
"Content-Type: text/plain; charset=ISO-8859-15; format=flowed\r\n",
|
299
|
+
"Content-Transfer-Encoding: 7bit\r\n",
|
300
|
+
"Organization: Arcor\r\n",
|
301
|
+
"NNTP-Posting-Date: 24 Apr 2007 14:39:11 CEST\r\n",
|
302
|
+
"NNTP-Posting-Host: 6cf11d8c.newsspool1.arcor-online.net\r\n",
|
303
|
+
"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",
|
304
|
+
"X-Complaints-To: usenet-abuse@arcor.de\r\n",
|
305
|
+
"Xref: sensor.twincode.net at.linux:1430\r\n",
|
306
|
+
".\r\n"
|
307
|
+
]
|
308
|
+
else
|
309
|
+
@io = ["412 No Group selected"]
|
310
|
+
end
|
311
|
+
else
|
312
|
+
@io = ["501 Bad Command"]
|
313
|
+
end
|
314
|
+
else
|
315
|
+
@io = ["500 Unknown Command"]
|
316
|
+
end
|
317
|
+
return str.length
|
318
|
+
end
|
319
|
+
|
320
|
+
def readline
|
321
|
+
super
|
322
|
+
@io.shift
|
323
|
+
end
|
324
|
+
|
325
|
+
private
|
326
|
+
def dp(x)
|
327
|
+
$stdout.puts x
|
328
|
+
end
|
329
|
+
|
330
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'net/nntp.rb'
|
3
|
+
|
4
|
+
class TestNNTPArticle < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@article = Net::NNTP::Article.new
|
8
|
+
@article.overview_format = "215 Order of fields in overview database.\r\nSubject:\r\nFrom:\r\nDate:\r\nMessage-ID:\r\nReferences:\r\nBytes:\r\nLines:\r\nXref:full\r\n.\r\n"
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_article_new
|
12
|
+
a = Net::NNTP::Article.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_article_id
|
16
|
+
@article.id = 1
|
17
|
+
assert_equal 1, @article.id
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_article_messageid
|
21
|
+
m = '<bla.foo@some.host>'
|
22
|
+
@article.messageid = m
|
23
|
+
assert_equal m, @article.messageid
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_article_subject
|
27
|
+
s = 'bla'
|
28
|
+
@article.subject = s
|
29
|
+
assert_equal s, @article.subject
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_from_xover
|
33
|
+
over = "1\tTesting\t\"abc\" abc@ide.invalid\t17 Aug 2004 14:00:00 GMT\t<this.post@is.invalid>\t\t200\t2\tXref: this.host.invalid alt.test:1"
|
34
|
+
@article.overview(over)
|
35
|
+
assert_equal '1', @article.id
|
36
|
+
assert_equal '<this.post@is.invalid>', @article.messageid
|
37
|
+
assert_equal 'Testing', @article.subject
|
38
|
+
assert_equal 200, @article.bytes.to_i
|
39
|
+
assert_equal 2, @article.lines.to_i
|
40
|
+
assert_equal '17 Aug 2004 14:00:00 GMT', @article.date
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_overview_fmt=
|
44
|
+
|
45
|
+
@article.overview_format = "215 Order of fields in overview database.\r\nSubject:\r\nFrom:\r\nDate:\r\nMessage-ID:\r\nReferences:\r\nBytes:\r\nLines:\r\nXref:full\r\n.\r\n"
|
46
|
+
assert_equal 'subject', @article.overview_format[1]
|
47
|
+
assert_equal 'from', @article.overview_format[2]
|
48
|
+
assert_equal 'date', @article.overview_format[3]
|
49
|
+
assert_equal 'messageid', @article.overview_format[4]
|
50
|
+
assert_equal 'references', @article.overview_format[5]
|
51
|
+
assert_equal 'bytes', @article.overview_format[6]
|
52
|
+
assert_equal 'lines', @article.overview_format[7]
|
53
|
+
assert_equal 'xref', @article.overview_format[8]
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'net/nntp'
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
class TestNNTPGroup< Test::Unit::TestCase
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@group = Net::NNTP::Group.new 'at.test'
|
11
|
+
@group = Net::NNTP::Group.new 'at.test'
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_init
|
15
|
+
assert_nothing_raised do
|
16
|
+
setup
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_name
|
21
|
+
assert_equal 'at.test', @group.name
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_first
|
25
|
+
@group.article_info = [100, 1, 101]
|
26
|
+
assert_equal 100, @group.article_count
|
27
|
+
assert_equal 1, @group.article_first
|
28
|
+
assert_equal 101, @group.article_last
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_listinfo
|
32
|
+
assert_nothing_raised do
|
33
|
+
@group.listinfo(10,20,'y')
|
34
|
+
assert_equal 10, @group.hi
|
35
|
+
assert_equal 20, @group.lo
|
36
|
+
assert_equal 'y', @group.postingmode
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_article
|
41
|
+
assert_equal 0, @group.articles.length
|
42
|
+
over = "1\tTesting\t\"abc\" abc@ide.invalid\t17 Aug 2004 14:00:00 GMT\t<this.post@is.invalid>\t\t200\t2\tXref: this.host.invalid alt.test:1"
|
43
|
+
@group.articles << Net::NNTP::Article.new
|
44
|
+
assert_equal 1, @group.articles.length
|
45
|
+
overview_format = "215 Order of fields in overview database.\r\nSubject:\r\nFrom:\r\nDate:\r\nMessage-ID:\r\nReferences:\r\nBytes:\r\nLines:\r\nXref:full\r\n.\r\n"
|
46
|
+
@group.articles.build_from_over(over, overview_format)
|
47
|
+
@group.articles = []
|
48
|
+
assert_equal 0, @group.articles.size
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_create
|
52
|
+
assert_kind_of Net::NNTP::Article, @group.articles.create
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_inspect
|
56
|
+
assert_kind_of String, @group.inspect
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: ruby-net-nntp
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.0.2
|
7
|
+
date: 2007-05-17 00:00:00 +02:00
|
8
|
+
summary: Net::XXX style NNTP Library for easy access.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: anton.bangratz@gmail.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: ""
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Anton Bangratz
|
31
|
+
files:
|
32
|
+
- lib/net
|
33
|
+
- lib/net/nntp.rb
|
34
|
+
- lib/net/nntp_article.rb
|
35
|
+
- lib/net/nntp_group.rb
|
36
|
+
- test/functional
|
37
|
+
- test/functional/test_nntp.rb
|
38
|
+
- test/mock
|
39
|
+
- test/mock/mock_socket.rb
|
40
|
+
- test/unit
|
41
|
+
- test/unit/test_nntp_article.rb
|
42
|
+
- test/unit/test_nntp_group.rb
|
43
|
+
- README
|
44
|
+
- CHANGELOG
|
45
|
+
- MIT-LICENSE
|
46
|
+
test_files:
|
47
|
+
- test/functional
|
48
|
+
- test/functional/test_nntp.rb
|
49
|
+
- test/mock
|
50
|
+
- test/mock/mock_socket.rb
|
51
|
+
- test/unit
|
52
|
+
- test/unit/test_nntp_article.rb
|
53
|
+
- test/unit/test_nntp_group.rb
|
54
|
+
rdoc_options:
|
55
|
+
- -S
|
56
|
+
- -N
|
57
|
+
- --main
|
58
|
+
- README
|
59
|
+
extra_rdoc_files:
|
60
|
+
- README
|
61
|
+
- CHANGELOG
|
62
|
+
- MIT-LICENSE
|
63
|
+
executables: []
|
64
|
+
|
65
|
+
extensions: []
|
66
|
+
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
dependencies: []
|
70
|
+
|