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 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
+