ruby-net-nntp 0.2.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +145 -128
- data/CHANGELOG.debian +5 -0
- data/Manifest.txt +37 -0
- data/README.txt +69 -0
- data/Rakefile +28 -0
- data/build-stamp +0 -0
- data/lib/net/nntp.rb +261 -327
- data/lib/net/nntp/request.rb +840 -0
- data/lib/net/nntp/response.rb +731 -0
- data/lib/net/nntp/version.rb +2 -1
- data/script/console +12 -0
- data/spec/net/nntp/request_spec.rb +771 -0
- data/spec/net/nntp/response_spec.rb +994 -0
- data/spec/net/nntp_spec.rb +634 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/stories/all.rb +2 -0
- data/spec/stories/helper.rb +17 -0
- data/spec/stories/net/nntp.rb +7 -0
- data/spec/stories/net/nntp.story +12 -0
- data/spec/stories/steps/nntp.rb +18 -0
- data/tasks/ann.rake +81 -0
- data/tasks/bones.rake +21 -0
- data/tasks/gem.rake +126 -0
- data/tasks/git.rake +41 -0
- data/tasks/manifest.rake +49 -0
- data/tasks/mercurial.rake +6 -0
- data/tasks/notes.rake +28 -0
- data/tasks/pallet.rake +17 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +268 -0
- data/tasks/spec.rake +55 -0
- data/tasks/svn.rake +48 -0
- data/tasks/test.rake +38 -0
- metadata +57 -33
- data/README +0 -46
- data/lib/net/nntp/article.rb +0 -188
- data/lib/net/nntp/group.rb +0 -83
- data/test/functional/test_nntp.rb +0 -288
- data/test/mock/mock_socket.rb +0 -359
- data/test/unit/test_nntp_article.rb +0 -98
- data/test/unit/test_nntp_group.rb +0 -60
data/build-stamp
ADDED
File without changes
|
data/lib/net/nntp.rb
CHANGED
@@ -1,407 +1,341 @@
|
|
1
|
-
# = Net::NNTP
|
1
|
+
# = Net::NNTP library
|
2
2
|
# Author:: Anton Bangratz
|
3
|
-
|
4
|
-
require 'thread'
|
5
|
-
require 'timeout' # :nodoc:
|
6
|
-
require 'net/nntp/group'
|
7
|
-
require 'net/nntp/article'
|
8
|
-
require 'net/nntp/version.rb'
|
3
|
+
#
|
9
4
|
require 'rubygems'
|
10
|
-
require '
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
require 'timeout'
|
6
|
+
require 'tmail'
|
7
|
+
require 'log4r'
|
8
|
+
require 'date'
|
9
|
+
require 'ostruct'
|
10
|
+
require 'net/nntp/version'
|
11
|
+
require 'net/nntp/request.rb'
|
12
|
+
require 'net/nntp/response.rb'
|
13
|
+
|
14
|
+
# Namespace
|
15
|
+
module Net
|
16
|
+
# Base class for connecting to an NNTP server and handling requests and responses.
|
15
17
|
class NNTP
|
16
|
-
include Timeout # :nodoc:
|
17
|
-
|
18
|
-
# Statuses of one-line responses
|
19
|
-
ONELINE_STATUSES = %w( 111 200 201 205 223 235 240 281 335 340 381 400 401 403 411 412 420 421 422 423 430 435 436 437 440 441 480 483 500 501 502 503 504 ).freeze
|
20
|
-
|
21
|
-
# Statuses of multiline responses
|
22
|
-
MULTILINE_STATUSES = %w( 100 101 215 220 221 222 224 225 230 231 ).freeze
|
23
|
-
|
24
|
-
# Error to indicate that NNTP Command failed gracefully
|
25
|
-
class CommandFailedError < StandardError
|
26
|
-
end
|
27
|
-
# Error to indicate that a Protocol Error occured during NNTP command execution
|
28
|
-
class ProtocolError < StandardError
|
29
|
-
end
|
30
18
|
|
19
|
+
attr_accessor :host, :port, :timeout
|
20
|
+
attr_reader :last_response, :current_group, :current_article
|
31
21
|
|
32
|
-
attr_reader :socket, :grouplist, :overview_format
|
33
|
-
attr_accessor :response_timeout
|
34
22
|
|
23
|
+
# Setter for a Log4r style logger.
|
35
24
|
def self.logger=(logger)
|
36
25
|
@@logger = logger
|
37
26
|
end
|
38
27
|
|
28
|
+
# Accessor for the Log4r style logger.
|
39
29
|
def self.logger
|
40
30
|
@@logger
|
41
31
|
end
|
42
32
|
|
43
|
-
|
44
|
-
@@logger
|
45
|
-
end
|
33
|
+
# Shortcut for Net::NNTP.logger.debug(message)
|
46
34
|
def debug(message)
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
# initializes NNTP class with host, port and timeout values
|
51
|
-
def initialize(host, port = 119, response_timeout = 10)
|
52
|
-
@host = host
|
53
|
-
@port = port
|
54
|
-
@response_timeout = response_timeout
|
55
|
-
@socket_class = TCPSocket
|
56
|
-
@group = nil
|
57
|
-
@@logger ||= Log4r::Logger['net::nntp'] || Log4r::Logger.new('net::nntp')
|
35
|
+
Net::NNTP.logger.debug(message)
|
58
36
|
end
|
59
37
|
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
@
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
38
|
+
# Initializes an NNTP instance.
|
39
|
+
#
|
40
|
+
# Takes an option hash as argument. Keys being processed are :host, :port and :timeout
|
41
|
+
def initialize(args={})
|
42
|
+
@host = args[:host] || default_host()
|
43
|
+
@port = args[:port] || default_port()
|
44
|
+
@timeout = args[:timeout] || default_timeout()
|
45
|
+
@current_request = nil
|
46
|
+
if block_given?
|
47
|
+
begin
|
48
|
+
yield self
|
49
|
+
ensure
|
50
|
+
close
|
51
|
+
end
|
52
|
+
end
|
71
53
|
end
|
72
54
|
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
55
|
+
# Sets up the connection to a TCPSocket, using #host and #port accessors.
|
56
|
+
#
|
57
|
+
# To use different server and port values, use the accessors.
|
58
|
+
#
|
59
|
+
# Reads and returns the response (should be a PostingOK or PostingProhibited response, or a generic response).
|
60
|
+
#
|
61
|
+
# == Usage Example
|
62
|
+
#
|
63
|
+
# nntp = Net::NNTP.new
|
64
|
+
# nntp.server = 'my.server.example.com'
|
65
|
+
# nntp.port = 22119
|
66
|
+
# if nntp.connect
|
67
|
+
# # ... do stuff ...
|
68
|
+
# end
|
69
|
+
def connect
|
70
|
+
@socket = TCPSocket.new(host(), port());
|
71
|
+
@connected = true
|
72
|
+
@current_request = nil
|
73
|
+
@last_response = read_response()
|
74
|
+
end
|
75
|
+
|
76
|
+
def reconnect
|
77
|
+
close unless @socket.closed?
|
78
|
+
connect
|
79
|
+
authenticate *@credentials if @credentials
|
80
|
+
process @current_group.request if @current_group
|
81
|
+
process @current_article.request if @current_article
|
79
82
|
end
|
80
83
|
|
81
|
-
|
82
|
-
# Closes connection. If not reconnected, subsequent calls of commands raise exceptions
|
83
84
|
def close
|
84
|
-
|
85
|
-
@socket.close unless socket.closed?
|
85
|
+
@socket.close unless @socket.closed?
|
86
86
|
end
|
87
87
|
|
88
|
-
|
89
|
-
|
88
|
+
# Returns true if #connect was successful and the socket is connected.
|
89
|
+
def connected?
|
90
|
+
@socket && !@socket.closed? && @connected
|
91
|
+
end
|
92
|
+
|
93
|
+
def read_response
|
94
|
+
begin
|
95
|
+
debug "reading from socket: #{@socket}"
|
96
|
+
line=nil
|
97
|
+
Timeout::timeout(@timeout) {
|
98
|
+
line = @socket.readline
|
99
|
+
}
|
100
|
+
debug("line from socket: #{line}")
|
101
|
+
response = Response.create(@current_request, line)
|
102
|
+
response
|
103
|
+
rescue EOFError
|
104
|
+
ensure
|
105
|
+
@current_request = nil
|
106
|
+
end
|
90
107
|
end
|
108
|
+
private :read_response
|
91
109
|
|
92
|
-
|
93
|
-
!help.select {|i| i =~ /\bover\b/i}.empty?
|
94
|
-
end
|
95
|
-
# Uses authinfo commands to authenticate. Timeout for first command is set to 10 seconds.
|
110
|
+
# Processes a request.
|
96
111
|
#
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
+
# +request+ must be a Net::NNTP::Request subclass. Certain requests (Authinfo and requests that require a two-stage
|
113
|
+
# response/request cycle will try to process these two stages gracefully. For multiline responses, the body will be
|
114
|
+
# processed, too.
|
115
|
+
#
|
116
|
+
# Net::NNTP::GroupSelected responses will be recorded in *current_group*, Net::NNTP::ArticleSelected responses in
|
117
|
+
# *current_article*.
|
118
|
+
#
|
119
|
+
# Returns the last response.
|
120
|
+
def process(request)
|
121
|
+
if connected?
|
122
|
+
@current_request = request
|
123
|
+
debug("Sending #{request.command}")
|
124
|
+
@socket.write(request.command)
|
125
|
+
@last_response = read_response()
|
126
|
+
if @last_response.needs_article?
|
127
|
+
debug "Sending article: #{request.dotstuff}"
|
128
|
+
request.dotstuff.split(/\r?\n/).each do |line|
|
129
|
+
line << "\r\n"
|
130
|
+
@socket.write line
|
131
|
+
end
|
132
|
+
@socket.write ".\r\n"
|
133
|
+
@last_response = read_response()
|
134
|
+
end
|
135
|
+
if (@last_response.multiline?)
|
136
|
+
debug "Response is multiline"
|
137
|
+
@last_response.body = @socket
|
138
|
+
end
|
139
|
+
@socket.close if @last_response.force_close?
|
140
|
+
@last_response
|
141
|
+
if (GroupSelected === @last_response)
|
142
|
+
@current_group = @last_response
|
143
|
+
elsif (ArticleSelected === @last_response)
|
144
|
+
@current_article = @last_response
|
145
|
+
else
|
146
|
+
@last_response
|
147
|
+
end
|
112
148
|
end
|
113
|
-
return response && response[0..2] == '281'
|
114
149
|
end
|
115
150
|
|
116
|
-
#
|
151
|
+
# Proxy for authentication request/response cycles.
|
117
152
|
#
|
118
|
-
#
|
153
|
+
# See Net::NNTP::Authinfo for parameters.
|
119
154
|
#
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
if
|
125
|
-
|
126
|
-
|
127
|
-
@group
|
155
|
+
# Returns +true+ if the authentication has been accepted.
|
156
|
+
def authenticate(user, pass)
|
157
|
+
@credentials = [user, pass]
|
158
|
+
auth_request = Authinfo.new('user', user)
|
159
|
+
if PasswordRequired === process(auth_request)
|
160
|
+
auth_request = Authinfo.new('pass', pass)
|
161
|
+
AuthenticationAccepted === process(auth_request)
|
128
162
|
else
|
129
|
-
|
163
|
+
false
|
130
164
|
end
|
131
165
|
end
|
132
166
|
|
133
|
-
#
|
134
|
-
|
135
|
-
|
136
|
-
|
167
|
+
# Proxy for Net::NNTP::Article requests and processing.
|
168
|
+
#
|
169
|
+
# See Net::NNTP::Article for parameters
|
170
|
+
#
|
171
|
+
# Returns the response.
|
172
|
+
def article(opts=nil)
|
173
|
+
request = Article.new(opts)
|
174
|
+
process(request)
|
137
175
|
end
|
138
176
|
|
139
|
-
#
|
140
|
-
# otherwise.
|
177
|
+
# Proxy for Net::NNTP::Body requests and processing.
|
141
178
|
#
|
142
|
-
#
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
else
|
149
|
-
@group.name != groupname
|
150
|
-
group(groupname)
|
151
|
-
end
|
152
|
-
cmd = "xhdr #{header}"
|
153
|
-
suffix = numbers_or_id(rest)
|
154
|
-
send_cmd([cmd, suffix].join(' '))
|
155
|
-
read_response()
|
179
|
+
# See Net::NNTP::Body for parameters
|
180
|
+
#
|
181
|
+
# Returns the response.
|
182
|
+
def body(opts)
|
183
|
+
request = Body.new(opts)
|
184
|
+
process(request)
|
156
185
|
end
|
157
186
|
|
158
|
-
#
|
159
|
-
# otherwise. If no group is selected nor given, raises error.
|
160
|
-
# Parameter 'rest' can be in the form of :from => number, :to => number or :messageid => 'messageid',
|
161
|
-
# if not set, a 'next' command is issued to the server prior to the xover command
|
187
|
+
# Proxy for Net::NNTP::Head requests and processing.
|
162
188
|
#
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
@group.name != groupname
|
170
|
-
group(groupname)
|
171
|
-
end
|
172
|
-
debug "Selected Group: #{@group.name}"
|
173
|
-
self.next unless rest
|
174
|
-
prefix = "xover"
|
175
|
-
suffix = numbers_or_id(rest)
|
176
|
-
cmd = [prefix, suffix].join ' '
|
177
|
-
send_cmd(cmd)
|
178
|
-
response = nil
|
179
|
-
timeout(@response_timeout) do
|
180
|
-
response = read_response()
|
181
|
-
end
|
182
|
-
response
|
189
|
+
# See Net::NNTP::Head for parameters
|
190
|
+
#
|
191
|
+
# Returns the response.
|
192
|
+
def head(opts)
|
193
|
+
request = Head.new(opts)
|
194
|
+
process(request)
|
183
195
|
end
|
184
196
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
debug gmt_str
|
191
|
-
cmd = 'newnews %s %s %s %s' % [groups, date, time, gmt_str]
|
192
|
-
debug "Sending #{cmd}"
|
193
|
-
send_cmd(cmd)
|
194
|
-
response = nil
|
195
|
-
response = read_response
|
196
|
-
response
|
197
|
+
# Proxy for Net::NNTP::Help requests and processing.
|
198
|
+
#
|
199
|
+
# Returns the response.
|
200
|
+
def help
|
201
|
+
process Help.new
|
197
202
|
end
|
198
203
|
|
199
|
-
#
|
200
|
-
# otherwise.
|
204
|
+
# Proxy for Net::NNTP::Last requests and processing.
|
201
205
|
#
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
group(groupname)
|
206
|
-
elsif @group.name != groupname
|
207
|
-
group(groupname)
|
208
|
-
end
|
209
|
-
debug "Selected Group: #{@group.name}"
|
210
|
-
send_cmd('listgroup')
|
211
|
-
read_response()
|
206
|
+
# Returns the response.
|
207
|
+
def last
|
208
|
+
process Last.new
|
212
209
|
end
|
213
210
|
|
214
|
-
#
|
215
|
-
#
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
def list(keyword=nil, pattern=nil)
|
220
|
-
cmd = ['list', keyword, pattern].join ' '
|
221
|
-
send_cmd(cmd)
|
222
|
-
list = read_response()
|
223
|
-
responsecode = list[0][0..2]
|
224
|
-
case responsecode
|
225
|
-
when '215'
|
226
|
-
case keyword
|
227
|
-
when /overview.fmt/
|
228
|
-
@overview_format_raw = list
|
229
|
-
@overview_format = Net::NNTP.parse_overview_format list
|
230
|
-
else
|
231
|
-
create_grouplist(list)
|
232
|
-
list
|
233
|
-
end
|
234
|
-
|
235
|
-
when '501', '503', '500'
|
236
|
-
raise CommandFailedError, list
|
237
|
-
end
|
211
|
+
# Proxy for Net::NNTP::Next requests and processing.
|
212
|
+
#
|
213
|
+
def next
|
214
|
+
process Next.new
|
238
215
|
end
|
239
216
|
|
240
|
-
#
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
unless ident[0..3] == 'xref'
|
248
|
-
overview_format << ident
|
249
|
-
else
|
250
|
-
overview_format << 'xref'
|
251
|
-
end
|
252
|
-
end
|
253
|
-
overview_format
|
217
|
+
# Proxy for Net::NNTP::Group requests and processing.
|
218
|
+
#
|
219
|
+
# See Net::NNTP::Group for parameters
|
220
|
+
#
|
221
|
+
# Returns the response.
|
222
|
+
def group(name)
|
223
|
+
process Group.new(name)
|
254
224
|
end
|
255
225
|
|
256
|
-
#
|
257
|
-
|
226
|
+
# Proxy for Net::NNTP::List requests and processing.
|
227
|
+
#
|
228
|
+
# See Net::NNTP::List for parameters
|
229
|
+
#
|
230
|
+
# Returns the response.
|
231
|
+
def list(keyword=nil, rest={})
|
232
|
+
process List.new(keyword, rest)
|
258
233
|
end
|
259
234
|
|
260
|
-
#
|
261
|
-
#
|
262
|
-
#
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
send_cmd(cmd)
|
268
|
-
response = read_response()
|
269
|
-
case response[0][0..2]
|
270
|
-
when '221'
|
271
|
-
return response
|
272
|
-
else
|
273
|
-
raise CommandFailedError, response
|
274
|
-
end
|
235
|
+
# Proxy for Net::NNTP::Listgroup request and processing
|
236
|
+
#
|
237
|
+
# See Net::NNTP::Listgroup for parameters
|
238
|
+
#
|
239
|
+
# Returns the response.
|
240
|
+
def listgroup(groupname=nil, range={})
|
241
|
+
process Listgroup.new(groupname, range)
|
275
242
|
end
|
276
243
|
|
277
|
-
#
|
278
|
-
#
|
279
|
-
|
280
|
-
|
281
|
-
def body(args=nil)
|
282
|
-
suffix = args
|
283
|
-
cmd = 'body'
|
284
|
-
cmd = ['body', suffix].join " " if suffix
|
285
|
-
send_cmd(cmd)
|
286
|
-
response = read_response()
|
287
|
-
case response[0][0..2]
|
288
|
-
when '222'
|
289
|
-
return response
|
290
|
-
else
|
291
|
-
raise CommandFailedError, response
|
292
|
-
end
|
244
|
+
# Proxy for Net::NNTP::Quit requests and processing.
|
245
|
+
#
|
246
|
+
def quit
|
247
|
+
process Quit.new
|
293
248
|
end
|
294
249
|
|
295
|
-
#
|
296
|
-
#
|
297
|
-
#
|
298
|
-
#
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
send_cmd(cmd)
|
304
|
-
response = read_response()
|
305
|
-
case response[0][0..2]
|
306
|
-
when '220'
|
307
|
-
return response
|
308
|
-
else
|
309
|
-
raise CommandFailedError, response
|
310
|
-
end
|
250
|
+
# Proxy for Net::NNTP::Stat requests and processing.
|
251
|
+
#
|
252
|
+
# See Net::NNTP::Stat for parameters
|
253
|
+
#
|
254
|
+
# Returns the response.
|
255
|
+
def stat(opts=nil)
|
256
|
+
request = Stat.new(opts)
|
257
|
+
process(request)
|
311
258
|
end
|
312
259
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
code, id, msgid, what = response.split
|
322
|
-
article.number = id
|
323
|
-
article.messageid = msgid
|
324
|
-
else
|
325
|
-
raise CommandFailedError, response
|
326
|
-
end
|
327
|
-
response
|
260
|
+
# Proxy for Net::NNTP::Hdr requests and processing.
|
261
|
+
#
|
262
|
+
# See Net::NNTP::Hdr for parameters
|
263
|
+
#
|
264
|
+
# Returns the response.
|
265
|
+
def hdr(field, opts)
|
266
|
+
request = Hdr.new(field, opts)
|
267
|
+
process(request)
|
328
268
|
end
|
329
269
|
|
330
|
-
#
|
331
|
-
|
332
|
-
|
270
|
+
# Proxy for Net::NNTP::Xhdr requests and processing.
|
271
|
+
#
|
272
|
+
# See Net::NNTP::Xhdr for parameters
|
273
|
+
#
|
274
|
+
# Returns the response.
|
275
|
+
def xhdr(field, opts)
|
276
|
+
request = Xhdr.new(field, opts)
|
277
|
+
process(request)
|
333
278
|
end
|
334
279
|
|
335
|
-
|
336
|
-
|
337
|
-
|
280
|
+
|
281
|
+
# Proxy for Net::NNTP::Over requests and processing.
|
282
|
+
#
|
283
|
+
# See Net::NNTP::Over for parameters
|
284
|
+
#
|
285
|
+
# Returns the response.
|
286
|
+
def over(range=nil)
|
287
|
+
request = Over.new(range)
|
288
|
+
process(request)
|
338
289
|
end
|
339
290
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
@grouplist[group.name] = group
|
349
|
-
end
|
350
|
-
@grouplist
|
291
|
+
# Proxy for Net::NNTP::Xover requests and processing.
|
292
|
+
#
|
293
|
+
# See Net::NNTP::Xover for parameters
|
294
|
+
#
|
295
|
+
# Returns the response.
|
296
|
+
def xover(range=nil)
|
297
|
+
request = Xover.new(range)
|
298
|
+
process(request)
|
351
299
|
end
|
352
300
|
|
353
|
-
|
354
|
-
|
355
|
-
|
301
|
+
|
302
|
+
# Proxy for Net::NNTP::Post requests and processing.
|
303
|
+
#
|
304
|
+
# See Net::NNTP::Post for parameters
|
305
|
+
#
|
306
|
+
# Returns the response.
|
307
|
+
def post(body)
|
308
|
+
request = Post.new
|
309
|
+
request.body = body
|
310
|
+
process(request)
|
356
311
|
end
|
357
312
|
|
358
|
-
|
359
|
-
#
|
360
|
-
#
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
linecnt += 1
|
373
|
-
end
|
374
|
-
debug "Response: '#{ra.inspect}'"
|
375
|
-
ra
|
313
|
+
|
314
|
+
# Proxy for Net::NNTP::Ihave requests and processing.
|
315
|
+
#
|
316
|
+
# See Net::NNTP::Ihave for parameters
|
317
|
+
#
|
318
|
+
# Returns the response.
|
319
|
+
def ihave(id, body)
|
320
|
+
request = Ihave.new id
|
321
|
+
request.body = body
|
322
|
+
process(request)
|
323
|
+
end
|
324
|
+
private
|
325
|
+
def default_host
|
326
|
+
'localhost'
|
376
327
|
end
|
377
328
|
|
378
|
-
|
379
|
-
|
380
|
-
# both are given
|
381
|
-
#
|
382
|
-
# Examples:
|
383
|
-
# numbers_or_id(:from => 1, :to => 100) #=> returns '1-100'
|
384
|
-
# numbers_or_id(:from => 1) #=> returns '1-'
|
385
|
-
# numbers_or_id(:message_id = '<abc>' #=> returns '<abc>'
|
386
|
-
# numbers_or_id(:from => 5, :message_id = '<abc>' #=> returns 'f-'
|
387
|
-
def numbers_or_id(hash)
|
388
|
-
return nil unless hash
|
389
|
-
suffix = ''
|
390
|
-
from = hash[:from]
|
391
|
-
to = hash[:to]
|
392
|
-
msgid = hash[:message_id]
|
393
|
-
if from
|
394
|
-
suffix = "#{from}-"
|
395
|
-
suffix += "#{to}" if to
|
396
|
-
elsif msgid
|
397
|
-
suffix = "#{msgid}"
|
398
|
-
end
|
399
|
-
suffix
|
329
|
+
def default_port
|
330
|
+
119
|
400
331
|
end
|
401
332
|
|
402
|
-
|
333
|
+
def default_timeout
|
334
|
+
15
|
335
|
+
end
|
403
336
|
|
404
337
|
end
|
405
338
|
end
|
406
339
|
|
340
|
+
|
407
341
|
# vim:sts=2:ts=2:sw=2:sta:et
|