ruby-net-nntp 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +38 -1
- data/README +9 -0
- data/lib/net/nntp.rb +31 -9
- data/lib/net/nntp/article.rb +176 -0
- data/lib/net/{nntp_group.rb → nntp/group.rb} +7 -0
- data/lib/net/nntp/version.rb +3 -3
- data/test/functional/test_nntp.rb +7 -7
- data/test/mock/mock_socket.rb +48 -48
- data/test/unit/test_nntp_article.rb +42 -8
- data/test/unit/test_nntp_group.rb +1 -1
- metadata +7 -5
- data/lib/net/nntp_article.rb +0 -28
data/CHANGELOG
CHANGED
@@ -1,4 +1,41 @@
|
|
1
|
-
2007-07-
|
1
|
+
2007-07-14 12:22 +0200 Anton 'tony' Bangratz <anton.bangratz@gmail.com> (5de9968582e9 [tip])
|
2
|
+
|
3
|
+
* README, lib/net/nntp.rb, lib/net/nntp/article.rb,
|
4
|
+
lib/net/nntp/group.rb, lib/net/nntp/version.rb,
|
5
|
+
test/mock/mock_socket.rb, test/unit/test_nntp_article.rb,
|
6
|
+
test/unit/test_nntp_group.rb:
|
7
|
+
NNTP can QUIT, Article redesign: parse HEAD, BODY and ARTICLE,
|
8
|
+
renamed 'id' to 'number', headers and body along with proxies added
|
9
|
+
- added QUIT to Net::NNTP
|
10
|
+
- added parse from HEAD, BODY and ARTICLE to Net::NNTP::Article
|
11
|
+
(factory)
|
12
|
+
- redesigned Net::NNTP::Article: + separate headers
|
13
|
+
and body attributes + including proxies to mimick
|
14
|
+
old attributes, deprecated + renamed the conflicting
|
15
|
+
'id' attribute to 'number'
|
16
|
+
- improved documentation
|
17
|
+
|
18
|
+
2007-07-09 14:34 +0200 Anton 'tony' Bangratz <anton.bangratz@gmail.com> (d97d95ec735b)
|
19
|
+
|
20
|
+
* lib/net/nntp.rb, lib/net/nntp/article.rb, lib/net/nntp/group.rb,
|
21
|
+
lib/net/nntp/version.rb, lib/net/nntp_article.rb,
|
22
|
+
lib/net/nntp_group.rb, test/functional/test_nntp.rb,
|
23
|
+
test/mock/mock_socket.rb:
|
24
|
+
fixed overview.fmt, fixed logging
|
25
|
+
- fixed overview.fmt bug
|
26
|
+
- fixed logging for autotest/test
|
27
|
+
|
28
|
+
2007-07-02 21:35 +0200 Anton 'tony' Bangratz <anton.bangratz@gmail.com> (5ba29ac12969)
|
29
|
+
|
30
|
+
* lib/net/nntp/version.rb:
|
31
|
+
new release;version fix
|
32
|
+
|
33
|
+
2007-07-02 21:34 +0200 Anton 'tony' Bangratz <anton.bangratz@gmail.com> (8441de3d244d)
|
34
|
+
|
35
|
+
* lib/net/nntp.rb:
|
36
|
+
bugfix read_response multiline read - introduced with last release
|
37
|
+
|
38
|
+
2007-07-02 20:51 +0200 Anton 'tony' Bangratz <anton.bangratz@gmail.com> (4399451e92c0)
|
2
39
|
|
3
40
|
* lib/net/nntp/version.rb:
|
4
41
|
Release 0.0.8, fixed version
|
data/README
CHANGED
@@ -29,3 +29,12 @@ Net::NNTP uses a simple interface to wrap commands to communicate with an NNTP s
|
|
29
29
|
|
30
30
|
* sudo gem install libruby-nntp or
|
31
31
|
* sudo dpkg -r libruby-0.0.1.deb
|
32
|
+
|
33
|
+
= CHANGES
|
34
|
+
|
35
|
+
Version 0.1.0 introduces the Net::NNTP::Article#headers and #body attributes.
|
36
|
+
Due to this, the attribute Net::NNTP::Article#id has been changed to Net::NNTP::Article#number
|
37
|
+
to avoid conflicts with Object#id.
|
38
|
+
|
39
|
+
Additionally, on request, Net::NNTP::Article has been changed from being a mere proxy for Net::NNTP#xover
|
40
|
+
result lines to being able to parse HEAD, BODY and ARTICLE results and return a corresponding instance.
|
data/lib/net/nntp.rb
CHANGED
@@ -3,13 +3,14 @@
|
|
3
3
|
require 'socket'
|
4
4
|
require 'thread'
|
5
5
|
require 'timeout' # :nodoc:
|
6
|
-
require 'net/
|
7
|
-
require 'net/
|
6
|
+
require 'net/nntp/group'
|
7
|
+
require 'net/nntp/article'
|
8
8
|
require 'net/nntp/version.rb'
|
9
9
|
require 'rubygems'
|
10
10
|
require 'log4r'
|
11
11
|
|
12
12
|
|
13
|
+
|
13
14
|
module Net
|
14
15
|
class NNTP
|
15
16
|
include Timeout # :nodoc:
|
@@ -62,6 +63,15 @@ module Net
|
|
62
63
|
@welcome
|
63
64
|
end
|
64
65
|
|
66
|
+
# Sends QUIT command to server and closes the connection (unless force_close is set to false). Returns response.
|
67
|
+
def quit(force_close=true)
|
68
|
+
send_cmd "QUIT"
|
69
|
+
response = read_response
|
70
|
+
close if force_close
|
71
|
+
response
|
72
|
+
end
|
73
|
+
|
74
|
+
|
65
75
|
# Closes connection. If not reconnected, subsequent calls of commands raise exceptions
|
66
76
|
def close
|
67
77
|
debug 'closing connection per request'
|
@@ -195,7 +205,7 @@ module Net
|
|
195
205
|
case keyword
|
196
206
|
when /overview.fmt/
|
197
207
|
@overview_format_raw = list
|
198
|
-
@overview_format = Net::NNTP.parse_overview_format list
|
208
|
+
@overview_format = Net::NNTP.parse_overview_format list
|
199
209
|
else
|
200
210
|
create_grouplist(list)
|
201
211
|
list
|
@@ -208,9 +218,10 @@ module Net
|
|
208
218
|
|
209
219
|
# prepares overview format as read from server, used by Net::NNTP::Article and list()
|
210
220
|
def self.parse_overview_format(format)
|
211
|
-
overview_format = %w{
|
212
|
-
|
213
|
-
|
221
|
+
overview_format = %w{number}
|
222
|
+
lines = format
|
223
|
+
lines.each do |line|
|
224
|
+
next if line[0] == ?2 || line[0] == ?. || line == 'full'
|
214
225
|
ident = line.scan(/\w/).join.downcase
|
215
226
|
unless ident[0..3] == 'xref'
|
216
227
|
overview_format << ident
|
@@ -287,7 +298,7 @@ module Net
|
|
287
298
|
case code
|
288
299
|
when '223'
|
289
300
|
code, id, msgid, what = response.split
|
290
|
-
article.
|
301
|
+
article.number = id
|
291
302
|
article.messageid = msgid
|
292
303
|
else
|
293
304
|
raise CommandFailedError, response
|
@@ -300,6 +311,7 @@ module Net
|
|
300
311
|
last_or_next("last")
|
301
312
|
end
|
302
313
|
|
314
|
+
# Issues the NEXT command to the NNTP server, returning the raw response
|
303
315
|
def next
|
304
316
|
last_or_next("next")
|
305
317
|
end
|
@@ -329,14 +341,24 @@ module Net
|
|
329
341
|
linecnt = 0
|
330
342
|
loop do
|
331
343
|
str = @socket.readline
|
344
|
+
#debug " -> got line: '#{str}'"
|
332
345
|
ra << str.chomp if str
|
333
|
-
break if force_oneline || (str.chomp == "." ||
|
346
|
+
break if force_oneline || (!str || str.chomp == "." || (linecnt == 0 && ONELINE_STATUSES.include?(str[0..2])) )
|
334
347
|
linecnt += 1
|
335
348
|
end
|
336
|
-
debug "Response: '#{ra}'"
|
349
|
+
debug "Response: '#{ra.inspect}'"
|
337
350
|
ra
|
338
351
|
end
|
339
352
|
|
353
|
+
# Parses a hash in the format {:from => int, :to => int} or {:message_id => int}
|
354
|
+
# and returns a string. :to is optional, :from has precedence over :message_id if
|
355
|
+
# both are given
|
356
|
+
#
|
357
|
+
# Examples:
|
358
|
+
# numbers_or_id(:from => 1, :to => 100) #=> returns '1-100'
|
359
|
+
# numbers_or_id(:from => 1) #=> returns '1-'
|
360
|
+
# numbers_or_id(:message_id = '<abc>' #=> returns '<abc>'
|
361
|
+
# numbers_or_id(:from => 5, :message_id = '<abc>' #=> returns 'f-'
|
340
362
|
def numbers_or_id(hash)
|
341
363
|
return nil unless hash
|
342
364
|
suffix = ''
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
# a slightly modified OpenStruct
|
4
|
+
class HeaderStruct < OpenStruct
|
5
|
+
# adds of modifies a new key/value pair
|
6
|
+
def add_pair(key, value)
|
7
|
+
@table[key.to_sym] = value
|
8
|
+
new_ostruct_member(key)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Net
|
13
|
+
class NNTP
|
14
|
+
class Article
|
15
|
+
attr_accessor :group, :headers, :body
|
16
|
+
attr_reader :overview_format
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@overview_format = %w{number}
|
20
|
+
@headers ||= HeaderStruct.new
|
21
|
+
@body = []
|
22
|
+
end
|
23
|
+
|
24
|
+
# Former versions attribute proxy
|
25
|
+
#
|
26
|
+
# Deprecated: use corresponding headers attribute instead
|
27
|
+
def number
|
28
|
+
@headers.number
|
29
|
+
end
|
30
|
+
|
31
|
+
# Former versions attribute proxy
|
32
|
+
#
|
33
|
+
# Deprecated: use corresponding headers attribute instead
|
34
|
+
def number=(number)
|
35
|
+
@headers.number = number
|
36
|
+
end
|
37
|
+
|
38
|
+
# Former versions attribute proxy
|
39
|
+
#
|
40
|
+
# Deprecated: use corresponding headers attribute instead
|
41
|
+
def messageid
|
42
|
+
@headers.message_id
|
43
|
+
end
|
44
|
+
|
45
|
+
# Former versions attribute proxy
|
46
|
+
#
|
47
|
+
# Deprecated: use corresponding headers attribute instead
|
48
|
+
def messageid=(id)
|
49
|
+
@headers.message_id = id
|
50
|
+
end
|
51
|
+
|
52
|
+
# Former versions attribute proxy
|
53
|
+
#
|
54
|
+
# Deprecated: use corresponding headers attribute instead
|
55
|
+
def subject
|
56
|
+
@headers.subject
|
57
|
+
end
|
58
|
+
|
59
|
+
# Former versions attribute proxy
|
60
|
+
#
|
61
|
+
# Deprecated: use corresponding headers attribute instead
|
62
|
+
def subject=(subject)
|
63
|
+
@headers.subject=subject
|
64
|
+
end
|
65
|
+
|
66
|
+
# Former versions attribute proxy
|
67
|
+
#
|
68
|
+
# Deprecated: use corresponding headers attribute instead
|
69
|
+
def bytes
|
70
|
+
@headers.bytes
|
71
|
+
end
|
72
|
+
|
73
|
+
# Former versions attribute proxy
|
74
|
+
#
|
75
|
+
# Deprecated: use corresponding headers attribute instead
|
76
|
+
def lines
|
77
|
+
@headers.lines
|
78
|
+
end
|
79
|
+
|
80
|
+
# Former versions attribute proxy
|
81
|
+
#
|
82
|
+
# Deprecated: use corresponding headers attribute instead
|
83
|
+
def xref
|
84
|
+
@headers.xref
|
85
|
+
end
|
86
|
+
|
87
|
+
# Former versions attribute proxy
|
88
|
+
#
|
89
|
+
# Deprecated: use corresponding headers attribute instead
|
90
|
+
def date
|
91
|
+
@headers.date
|
92
|
+
end
|
93
|
+
|
94
|
+
# Former versions attribute proxy
|
95
|
+
#
|
96
|
+
# Deprecated: use corresponding headers attribute instead
|
97
|
+
def from
|
98
|
+
@headers.from
|
99
|
+
end
|
100
|
+
|
101
|
+
# Sets the overview format to use for parsing article from XOVER command results.
|
102
|
+
#
|
103
|
+
#
|
104
|
+
# Takes either a tab separated line as result from 'LIST OVERVIEW.FMT' and
|
105
|
+
# parses it into an array (see Net::NNTP::parse_overview_format) or takes
|
106
|
+
# an already parsed array to set the format directly.
|
107
|
+
def overview_format=(format)
|
108
|
+
if Array === format
|
109
|
+
@overview_format = format
|
110
|
+
else
|
111
|
+
@overview_format = Net::NNTP.parse_overview_format format
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Parses data from XOVER command
|
116
|
+
#
|
117
|
+
# Takes the tab separated line corresponding to an article from the XOVER command
|
118
|
+
# result and sets the header fields accordingly. CAVEAT! The overview format (see
|
119
|
+
# Net::NNTP::Article#overview_format= has to be set prior of attempting this, and
|
120
|
+
# has to actually correspond with the fields.
|
121
|
+
def overview(over)
|
122
|
+
over.split(/\t/).each_with_index do |value, index|
|
123
|
+
ident = @overview_format[index]
|
124
|
+
@headers.add_pair(ident, value)
|
125
|
+
if @headers.messageid
|
126
|
+
@headers.message_id = @headers.messageid
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Sets a header from the result line
|
132
|
+
#
|
133
|
+
# Parses a line of the format "Header: Value" and sets the @headers accordingly.
|
134
|
+
# (Example: "Message-ID: <abc@def.gh>" will become @headers.message_id with the
|
135
|
+
# value '<abc@def.gh>'.
|
136
|
+
def set_header(line)
|
137
|
+
name, value = line.scan(/^(.*)?: (.*)$/).flatten
|
138
|
+
key = name.strip.gsub(/[^\w]/, '_').downcase
|
139
|
+
@headers.add_pair(key, value)
|
140
|
+
@headers
|
141
|
+
end
|
142
|
+
|
143
|
+
# Creates an Net::NNTP::Article from a HEAD, BODY or ARTICLE result
|
144
|
+
#
|
145
|
+
# Takes the full result (including response line and stop marker ".")
|
146
|
+
# and creates a Net::NNTP::Article instance with the headers in @headers and
|
147
|
+
# the body in @body.
|
148
|
+
def self.parse(lines)
|
149
|
+
responsecode = lines[0][0..2]
|
150
|
+
do_header = responsecode == '221'
|
151
|
+
do_body = responsecode == '222'
|
152
|
+
if responsecode == '220'
|
153
|
+
do_header = do_body = true
|
154
|
+
end
|
155
|
+
article = Net::NNTP::Article.new
|
156
|
+
count = 0
|
157
|
+
lines.each do |line|
|
158
|
+
count += 1
|
159
|
+
next if count == 1
|
160
|
+
break if line =~ /^.$/
|
161
|
+
do_header = (do_header && line !~ /^$/)
|
162
|
+
next if line =~ /^$/
|
163
|
+
if do_header
|
164
|
+
article.set_header(line)
|
165
|
+
else
|
166
|
+
if do_body
|
167
|
+
article.body << line
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
article
|
172
|
+
end
|
173
|
+
|
174
|
+
end # class Net::NNTP::Article
|
175
|
+
end
|
176
|
+
end
|
@@ -13,6 +13,9 @@ module Net
|
|
13
13
|
@article_first = @article_last = @article_count = nil
|
14
14
|
end
|
15
15
|
|
16
|
+
# Set article_count, article_first, article_last (from GROUP command)
|
17
|
+
#
|
18
|
+
# Takes an array [count, first, last] as argument
|
16
19
|
def article_info=(art_array)
|
17
20
|
@article_count = art_array[0].to_i
|
18
21
|
@article_first = art_array[1].to_i
|
@@ -27,6 +30,7 @@ module Net
|
|
27
30
|
@articles = articles
|
28
31
|
end
|
29
32
|
|
33
|
+
# Sets hi and lo watermark alont with postingmode (from LIST ACTIVE command)
|
30
34
|
def listinfo(hi, lo, postingmode)
|
31
35
|
@hi = hi
|
32
36
|
@lo = lo
|
@@ -45,6 +49,7 @@ module Net
|
|
45
49
|
@articles ||=[]
|
46
50
|
end
|
47
51
|
|
52
|
+
# Stores articles in group attribute, using Net::NNTP::Article instances
|
48
53
|
def build_from_over(over, format)
|
49
54
|
article = Article.new
|
50
55
|
article.overview_format = format
|
@@ -60,6 +65,8 @@ module Net
|
|
60
65
|
@articles << article
|
61
66
|
end
|
62
67
|
|
68
|
+
# Creates one Net::NNTP::Article instance, sets the group attribute to the
|
69
|
+
# including group instances and adds the article to articles before returning it
|
63
70
|
def create
|
64
71
|
a = Article.new
|
65
72
|
a.group = self.group
|
data/lib/net/nntp/version.rb
CHANGED
@@ -4,18 +4,18 @@ require 'net/nntp.rb'
|
|
4
4
|
require 'mock/mock_socket'
|
5
5
|
|
6
6
|
|
7
|
+
unless defined? log
|
8
|
+
log = Log4r::Logger.new('net::nntp')
|
9
|
+
fileout = Log4r::FileOutputter.new('net::nntp::fileout', :filename => File.join('logs', 'autotest.log'), :trunc => true)
|
10
|
+
fileout.formatter = Log4r::PatternFormatter.new(:pattern => '%d [%5l] : %m')
|
11
|
+
log.add fileout
|
12
|
+
log.level = Log4r::ALL
|
13
|
+
end
|
7
14
|
|
8
15
|
module TestNet
|
9
16
|
class TestNNTP < Test::Unit::TestCase
|
10
17
|
|
11
18
|
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
19
|
nntp_connect_and_auth('localhost', 119, 'dummy', 'test')
|
20
20
|
end
|
21
21
|
|
data/test/mock/mock_socket.rb
CHANGED
@@ -105,7 +105,7 @@ class MockSocket < Test::Unit::MockObject( TCPSocket )
|
|
105
105
|
when /^list\b\s*(.*)\r\n$/
|
106
106
|
case $1
|
107
107
|
when /overview.fmt/i
|
108
|
-
@io = ["215 Order of fields in overview database.\r\
|
108
|
+
@io = ["215 Order of fields in overview database.\r\n", "Subject:\r\n", "From:\r\n", "Date:\r\n", "Message-ID:\r\n", "References:\r\n", "Bytes:\r\n", "Lines:\r\n", "Xref:full\r\n", ".\r\n" ]
|
109
109
|
when /active\s*(.*)/
|
110
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
111
|
when /^\s*$/
|
@@ -186,10 +186,10 @@ class MockSocket < Test::Unit::MockObject( TCPSocket )
|
|
186
186
|
"1374\r\n",
|
187
187
|
"1375\r\n",
|
188
188
|
".\r\n"
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
189
|
+
]
|
190
|
+
else
|
191
|
+
if @group_selected
|
192
|
+
@io = [
|
193
193
|
"211 Article list for at.linux follows\r\n",
|
194
194
|
"1363\r\n",
|
195
195
|
"1364\r\n",
|
@@ -205,31 +205,31 @@ class MockSocket < Test::Unit::MockObject( TCPSocket )
|
|
205
205
|
"1374\r\n",
|
206
206
|
"1375\r\n",
|
207
207
|
".\r\n"
|
208
|
-
|
208
|
+
]
|
209
|
+
else
|
210
|
+
@io = ['412 No Group selected']
|
211
|
+
end
|
212
|
+
end
|
213
|
+
when "quit\r\n" then
|
214
|
+
@io = ["200 Good bye"]
|
215
|
+
when "authinfo user dummy\r\n"
|
216
|
+
@io = ["381 More authentication details needed"]
|
217
|
+
when "authinfo pass test\r\n"
|
218
|
+
@io = ["281 Welcome to dummytest"]
|
219
|
+
when /^group\s+(.+)\s*\r\n$/
|
220
|
+
case $1
|
221
|
+
when 'at.linux'
|
222
|
+
@io = ["211 12 1363 1375 at.linux"]
|
223
|
+
@group_selected = 'at.linux'
|
209
224
|
else
|
210
|
-
@io = [
|
225
|
+
@io = ["411 No such group"]
|
211
226
|
end
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
@io = ["281 Welcome to dummytest"]
|
219
|
-
when /^group\s+(.+)\s*\r\n$/
|
220
|
-
case $1
|
221
|
-
when 'at.linux'
|
222
|
-
@io = ["211 12 1363 1375 at.linux"]
|
223
|
-
@group_selected = 'at.linux'
|
224
|
-
else
|
225
|
-
@io = ["411 No such group"]
|
226
|
-
end
|
227
|
-
when "xhdr subject <slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>\r\n"
|
228
|
-
@io =
|
229
|
-
["1375 Re: Bitte um Meinungen ==> Virtualisierung\r\n"]
|
230
|
-
when "xhdr subject 1363-1375\r\n"
|
231
|
-
if @group_selected
|
232
|
-
@io = [
|
227
|
+
when "xhdr subject <slrnf26akq.ci5.hjp-usenet2@zeno.hjp.at>\r\n"
|
228
|
+
@io =
|
229
|
+
["1375 Re: Bitte um Meinungen ==> Virtualisierung\r\n"]
|
230
|
+
when "xhdr subject 1363-1375\r\n"
|
231
|
+
if @group_selected
|
232
|
+
@io = [
|
233
233
|
"221 Subject header (from overview) for postings 1363-1375\r\n",
|
234
234
|
"1363 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
235
235
|
"1364 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
@@ -245,11 +245,11 @@ class MockSocket < Test::Unit::MockObject( TCPSocket )
|
|
245
245
|
"1374 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
246
246
|
"1375 Re: Bitte um Meinungen ==> Virtualisierung\r\n",
|
247
247
|
".\r\n"
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
248
|
+
]
|
249
|
+
else
|
250
|
+
@io = ['412 No group selected']
|
251
|
+
end
|
252
|
+
when "xover 1363-1375\r\n"
|
253
253
|
if @group_selected
|
254
254
|
@io = [
|
255
255
|
"224 Overview information for postings 1363-1375:\r\n",
|
@@ -267,9 +267,9 @@ class MockSocket < Test::Unit::MockObject( TCPSocket )
|
|
267
267
|
"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",
|
268
268
|
"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",
|
269
269
|
".\r\n"
|
270
|
-
|
271
|
-
|
272
|
-
|
270
|
+
]
|
271
|
+
else
|
272
|
+
@io = ["412 No Group selected"]
|
273
273
|
end
|
274
274
|
when /xover \<.+\>/
|
275
275
|
@io = ["502 Usage: OVER first[-[last]]"]
|
@@ -300,11 +300,11 @@ class MockSocket < Test::Unit::MockObject( TCPSocket )
|
|
300
300
|
"X-Complaints-To: usenet-abuse@arcor.de\r\n",
|
301
301
|
"Xref: sensor.twincode.net at.linux:1430\r\n",
|
302
302
|
".\r\n"
|
303
|
-
|
303
|
+
]
|
304
304
|
|
305
305
|
when /^\s?$/
|
306
|
-
|
307
|
-
|
306
|
+
if @group_selected
|
307
|
+
@io = [
|
308
308
|
"221 1430 <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net> article retrieved - head follows\r\n",
|
309
309
|
"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",
|
310
310
|
"Message-ID: <462dfa6f$0$23135$9b4e6d93@newsspool1.arcor-online.net>\r\n",
|
@@ -326,18 +326,18 @@ class MockSocket < Test::Unit::MockObject( TCPSocket )
|
|
326
326
|
"X-Complaints-To: usenet-abuse@arcor.de\r\n",
|
327
327
|
"Xref: sensor.twincode.net at.linux:1430\r\n",
|
328
328
|
".\r\n"
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
329
|
+
]
|
330
|
+
else
|
331
|
+
@io = ["412 No Group selected"]
|
332
|
+
end
|
333
333
|
else
|
334
334
|
@io = ["501 Bad Command"]
|
335
335
|
end
|
336
|
-
|
337
|
-
|
338
|
-
end
|
339
|
-
return str.length
|
336
|
+
else
|
337
|
+
@io = ["500 Unknown Command"]
|
340
338
|
end
|
339
|
+
return str.length
|
340
|
+
end
|
341
341
|
|
342
342
|
def readline
|
343
343
|
super
|
@@ -349,4 +349,4 @@ class MockSocket < Test::Unit::MockObject( TCPSocket )
|
|
349
349
|
$stdout.puts x
|
350
350
|
end
|
351
351
|
|
352
|
-
|
352
|
+
end
|
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'net/nntp.rb'
|
3
|
-
|
4
1
|
class TestNNTPArticle < Test::Unit::TestCase
|
5
2
|
|
6
3
|
def setup
|
@@ -12,9 +9,9 @@ class TestNNTPArticle < Test::Unit::TestCase
|
|
12
9
|
a = Net::NNTP::Article.new
|
13
10
|
end
|
14
11
|
|
15
|
-
def
|
16
|
-
@article.
|
17
|
-
assert_equal 1, @article.
|
12
|
+
def test_article_number
|
13
|
+
@article.number = 1
|
14
|
+
assert_equal 1, @article.number
|
18
15
|
end
|
19
16
|
|
20
17
|
def test_article_messageid
|
@@ -32,7 +29,7 @@ class TestNNTPArticle < Test::Unit::TestCase
|
|
32
29
|
def test_from_xover
|
33
30
|
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
31
|
@article.overview(over)
|
35
|
-
assert_equal '1', @article.
|
32
|
+
assert_equal '1', @article.number
|
36
33
|
assert_equal '<this.post@is.invalid>', @article.messageid
|
37
34
|
assert_equal 'Testing', @article.subject
|
38
35
|
assert_equal 200, @article.bytes.to_i
|
@@ -41,8 +38,8 @@ class TestNNTPArticle < Test::Unit::TestCase
|
|
41
38
|
end
|
42
39
|
|
43
40
|
def test_overview_fmt=
|
44
|
-
|
45
41
|
@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"
|
42
|
+
assert_equal 'number', @article.overview_format[0]
|
46
43
|
assert_equal 'subject', @article.overview_format[1]
|
47
44
|
assert_equal 'from', @article.overview_format[2]
|
48
45
|
assert_equal 'date', @article.overview_format[3]
|
@@ -53,4 +50,41 @@ class TestNNTPArticle < Test::Unit::TestCase
|
|
53
50
|
assert_equal 'xref', @article.overview_format[8]
|
54
51
|
end
|
55
52
|
|
53
|
+
def test_set_header
|
54
|
+
@article.set_header('Subject: Test')
|
55
|
+
assert_equal 'Test', @article.headers.subject
|
56
|
+
@article.set_header('Message-ID: <this.post@is.invalid>')
|
57
|
+
assert_equal '<this.post@is.invalid>', @article.headers.message_id
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_parse
|
61
|
+
article = Net::NNTP::Article.parse(["220 1 article retrieved - text follows",
|
62
|
+
"Date: 17 Aug 2004 14:00:00 GMT",
|
63
|
+
"From: \"abc\" abc@ide.invalid",
|
64
|
+
"Message-ID: <this.post@is.invalid>",
|
65
|
+
"Subject: ignore test",
|
66
|
+
"",
|
67
|
+
"test please ignore",
|
68
|
+
"test ",
|
69
|
+
"."])
|
70
|
+
assert_equal '17 Aug 2004 14:00:00 GMT', article.headers.date
|
71
|
+
assert_equal '"abc" abc@ide.invalid', article.headers.from
|
72
|
+
assert_equal '<this.post@is.invalid>', article.headers.message_id
|
73
|
+
assert_equal 'ignore test', article.headers.subject
|
74
|
+
assert_equal 2, article.body.size
|
75
|
+
assert_equal 'test please ignore', article.body[0]
|
76
|
+
assert_equal 'test ', article.body[1]
|
77
|
+
article = Net::NNTP::Article.parse(["221 1 article retrieved - head follows", "Date: 17 Aug 2004 14:00:00 GMT", "From: \"abc\" abc@ide.invalid",
|
78
|
+
"Message-ID: <this.post@is.invalid>", "Subject: ignore test", "."])
|
79
|
+
assert_equal '17 Aug 2004 14:00:00 GMT', article.headers.date
|
80
|
+
assert_equal '"abc" abc@ide.invalid', article.headers.from
|
81
|
+
assert_equal '<this.post@is.invalid>', article.headers.message_id
|
82
|
+
assert_equal 'ignore test', article.headers.subject
|
83
|
+
assert_equal 0, article.body.size
|
84
|
+
article = Net::NNTP::Article.parse(["222 1 article retrieved - body follows", "test please ignore", "test ", "."])
|
85
|
+
assert_equal 2, article.body.size
|
86
|
+
assert_equal 'test please ignore', article.body[0]
|
87
|
+
assert_equal 'test ', article.body[1]
|
88
|
+
end
|
89
|
+
|
56
90
|
end
|
metadata
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.0
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby-net-nntp
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0
|
7
|
-
date: 2007-07-
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2007-07-14 00:00:00 +02:00
|
8
8
|
summary: Net::XXX style NNTP Library for easy access.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -31,9 +31,9 @@ authors:
|
|
31
31
|
files:
|
32
32
|
- lib/net
|
33
33
|
- lib/net/nntp
|
34
|
+
- lib/net/nntp/article.rb
|
35
|
+
- lib/net/nntp/group.rb
|
34
36
|
- lib/net/nntp/version.rb
|
35
|
-
- lib/net/nntp_article.rb
|
36
|
-
- lib/net/nntp_group.rb
|
37
37
|
- lib/net/nntp.rb
|
38
38
|
- test/functional
|
39
39
|
- test/functional/test_nntp.rb
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- test/unit
|
43
43
|
- test/unit/test_nntp_article.rb
|
44
44
|
- test/unit/test_nntp_group.rb
|
45
|
+
- test/logs
|
45
46
|
- README
|
46
47
|
- CHANGELOG
|
47
48
|
- MIT-LICENSE
|
@@ -53,6 +54,7 @@ test_files:
|
|
53
54
|
- test/unit
|
54
55
|
- test/unit/test_nntp_article.rb
|
55
56
|
- test/unit/test_nntp_group.rb
|
57
|
+
- test/logs
|
56
58
|
rdoc_options:
|
57
59
|
- -S
|
58
60
|
- -N
|
data/lib/net/nntp_article.rb
DELETED
@@ -1,28 +0,0 @@
|
|
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, :from
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@overview_format = %w{id}
|
9
|
-
end
|
10
|
-
|
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
|
-
|
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
|
-
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|