Class: Net::NNTP

Inherits:
Object
  • Object
show all
Includes:
Timeout
Defined in:
lib/net/nntp.rb,
lib/net/nntp/group.rb,
lib/net/nntp/article.rb,
lib/net/nntp/version.rb

Defined Under Namespace

Classes: Article, CommandFailedError, Group, ProtocolError

Constant Summary collapse

ONELINE_STATUSES =

Statuses of one-line responses

%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
MULTILINE_STATUSES =

Statuses of multiline responses

%w( 100 101 215 220 221 222 224 225 230 231 ).freeze
VERSION =
"0.2.0"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(host, port = 119, response_timeout = 10) ⇒ NNTP

initializes NNTP class with host, port and timeout values



51
52
53
54
55
56
57
58
# File 'lib/net/nntp.rb', line 51

def initialize(host, port = 119, response_timeout = 10)
  @host = host
  @port = port
  @response_timeout = response_timeout
  @socket_class = TCPSocket
  @group = nil
  @@logger ||= Log4r::Logger['net::nntp'] || Log4r::Logger.new('net::nntp')
end

Instance Attribute Details

#grouplistObject (readonly)

Returns the value of attribute grouplist.



32
33
34
# File 'lib/net/nntp.rb', line 32

def grouplist
  @grouplist
end

#overview_formatObject (readonly)

Returns the value of attribute overview_format.



32
33
34
# File 'lib/net/nntp.rb', line 32

def overview_format
  @overview_format
end

#response_timeoutObject

Returns the value of attribute response_timeout.



33
34
35
# File 'lib/net/nntp.rb', line 33

def response_timeout
  @response_timeout
end

#socketObject (readonly)

Returns the value of attribute socket.



32
33
34
# File 'lib/net/nntp.rb', line 32

def socket
  @socket
end

Class Method Details

.loggerObject



39
40
41
# File 'lib/net/nntp.rb', line 39

def self.logger
  @@logger
end

.logger=(logger) ⇒ Object



35
36
37
# File 'lib/net/nntp.rb', line 35

def self.logger=(logger)
  @@logger = logger
end

.parse_overview_format(format) ⇒ Object

prepares overview format as read from server, used by Net::NNTP::Article and list()



236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/net/nntp.rb', line 236

def self.parse_overview_format(format)
  overview_format = %w{number}
  lines = format
  lines.each do |line|
    next if line[0] == ?2 || line[0] == ?. || line == 'full'
    ident = line.scan(/\w/).join.downcase
    unless ident[0..3] == 'xref'
      overview_format << ident 
    else
      overview_format << 'xref'
    end
  end
  overview_format
end

Instance Method Details

#article(args = nil) ⇒ Object

Issues ‘ARTICLE’ command to NNTP server, returning raw response.

options

messageid|id

Throws CommandFailedError



294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/net/nntp.rb', line 294

def article(args=nil)
  suffix = args
  cmd = 'article'
  cmd = ['article', suffix].join " " if suffix
  send_cmd(cmd)
  response = read_response()
  case response[0][0..2]
  when '220'
    return response
  else
    raise CommandFailedError, response
  end
end

#authenticate(user, pass) ⇒ Object

Uses authinfo commands to authenticate. Timeout for first command is set to 10 seconds.

Returns true on success, false on failure.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/net/nntp.rb', line 93

def authenticate(user, pass)
  cmd = "authinfo user #{user}"
  debug "Authenticating: Sending #{cmd}"
  send_cmd cmd
  response_array = read_response()
  response = response_array[0]
  debug "Authenticating: Response #{response}"
  if response[0..2] == '381' then
    cmd = "authinfo pass #{pass}"
    debug "Authenticating: Sending #{cmd}"
    send_cmd cmd
    response_array = read_response()
    response = response_array[0]
    debug "Authenticating: Response #{response}"
  end
  return response && response[0..2] == '281'
end

#body(args = nil) ⇒ Object

Issues ‘BODY’ command to NNTP server, returning raw response.

options

messageid|id

Throws CommandFailedError



276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/net/nntp.rb', line 276

def body(args=nil)
  suffix = args
  cmd = 'body'
  cmd = ['body', suffix].join " " if suffix
  send_cmd(cmd)
  response = read_response()
  case response[0][0..2]
  when '222'
    return response
  else
    raise CommandFailedError, response
  end
end

#closeObject

Closes connection. If not reconnected, subsequent calls of commands raise exceptions



78
79
80
81
# File 'lib/net/nntp.rb', line 78

def close
  debug 'closing connection per request'
  @socket.close unless socket.closed?
end

#connectObject

Actually connects to NNTP host and port given in new()



61
62
63
64
65
66
# File 'lib/net/nntp.rb', line 61

def connect
  @socket = @socket_class.new(@host, @port)
  @welcome = read_response()
  debug "Welcome: #{@welcome[0]} "
  @welcome
end

#debug(message) ⇒ Object



46
47
48
# File 'lib/net/nntp.rb', line 46

def debug(message)
  @@logger.debug(message)
end

#group(group) ⇒ Object

Issues ‘GROUP’ command to NNTP Server and creates new active group from returning data.

Throws CommandFailedError



115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/net/nntp.rb', line 115

def group(group)
  send_cmd "group #{group}"
  response = read_response(true)
  responsecode, cnt, first, last, name = response[0].split
  if responsecode == '211'
    @group = Group.new(name)
    @group. = [cnt, first, last]
    @group
  else
    raise CommandFailedError, response[0]
  end
end

#has_over?Boolean

Returns:

  • (Boolean)


87
88
89
# File 'lib/net/nntp.rb', line 87

def has_over?
  !help.select {|i| i =~ /\bover\b/i}.empty?
end

#has_xover?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/net/nntp.rb', line 83

def has_xover?
  !help.select {|i| i =~ /\bxover\b/i}.empty?
end

#head(args = nil) ⇒ Object

Issues ‘HEAD’ command to NNTP server, returning raw response

Throws CommandFailedError



258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/net/nntp.rb', line 258

def head(args=nil)
  suffix = numbers_or_id(args)
  cmd = 'head'
  cmd = ['head', suffix].join " " if suffix
  send_cmd(cmd)
  response = read_response()
  case response[0][0..2]
  when '221'
    return response
  else
    raise CommandFailedError, response
  end
end

#helpObject

Issues ‘HELP’ command to NNTP Server, and returns raw response.



129
130
131
132
# File 'lib/net/nntp.rb', line 129

def help
  send_cmd("help")
  read_response()
end

#lastObject

Issues the LAST command to the NNTP server, returning the raw response



326
327
328
# File 'lib/net/nntp.rb', line 326

def last
  last_or_next("last")
end

#list(keyword = nil, pattern = nil) ⇒ Object

Issues ‘LIST’ command to NNTP Server. Depending on server capabilities and given keyword, can either set overview format (if called with ‘overview.fmt’) or create a grouplist (see Attributes)

Throws CommandFailedError



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/net/nntp.rb', line 214

def list(keyword=nil, pattern=nil)
  cmd = ['list', keyword, pattern].join ' '
  send_cmd(cmd)
  list = read_response()
  responsecode = list[0][0..2]
  case responsecode 
  when '215'
    case keyword
    when /overview.fmt/
      @overview_format_raw = list
      @overview_format = Net::NNTP.parse_overview_format list
    else
      create_grouplist(list)
      list
    end

  when '501', '503', '500'
    raise CommandFailedError, list
  end
end

#listgroup(groupname = nil) ⇒ Object

Issues ‘LISTGROUP’ command to NNTP Server, and returns raw response. Checks if group has been selected, selects group otherwise.

Raises:



197
198
199
200
201
202
203
204
205
206
207
# File 'lib/net/nntp.rb', line 197

def listgroup(groupname=nil)
  raise CommandFailedError, 'No group selected' unless @group || groupname
  if @group.nil?
    group(groupname) 
  elsif @group.name != groupname
    group(groupname)
  end
  debug "Selected Group: #{@group.name}"
  send_cmd('listgroup')
  read_response()
end

#loggerObject



43
44
45
# File 'lib/net/nntp.rb', line 43

def logger
  @@logger
end

#newnews(groups = '*', date = nil, time = nil, gmt = true) ⇒ Object



180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/net/nntp.rb', line 180

def newnews(groups='*', date=nil, time=nil, gmt=true)
  gmt_str = gmt ? '"GMT"' : "" 
  debug groups
  debug date
  debug time
  debug gmt_str
  cmd = 'newnews %s %s %s %s' % [groups, date, time, gmt_str]
  debug "Sending #{cmd}"
  send_cmd(cmd)
  response = nil
  response = read_response
  response
end

#nextObject

Issues the NEXT command to the NNTP server, returning the raw response



331
332
333
# File 'lib/net/nntp.rb', line 331

def next
  last_or_next("next")
end

#quit(force_close = true) ⇒ Object

Sends QUIT command to server and closes the connection (unless force_close is set to false). Returns response.



69
70
71
72
73
74
# File 'lib/net/nntp.rb', line 69

def quit(force_close=true)
  send_cmd "QUIT"
  response = read_response
  close if force_close
  response
end

#statObject

TODO: complete implementation



252
253
# File 'lib/net/nntp.rb', line 252

def stat
end

#xhdr(header, groupname = nil, rest = nil) ⇒ Object

Issues ‘XHDR’ command to NNTP Server, and returns raw response. Checks if group has been selected, selects group otherwise.

TODO

Implement XHDR header <message-id>

Raises:



138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/net/nntp.rb', line 138

def xhdr(header, groupname=nil, rest=nil)
  raise CommandFailedError, 'No group selected' unless @group || groupname
  if @group.nil?
    group(groupname) 
  elsif groupname.nil?
  else
    @group.name != groupname
    group(groupname)
  end
  cmd = "xhdr #{header}"
  suffix = numbers_or_id(rest)
  send_cmd([cmd, suffix].join(' '))
  read_response()
end

#xover(groupname = nil, rest = nil) ⇒ Object

Issues ‘XOVER’ command to NNTP Server, and returns raw response. Checks if group has been selected, selects group otherwise. If no group is selected nor given, raises error. Parameter ‘rest’ can be in the form of :from => number, :to => number or :messageid => ‘messageid’, if not set, a ‘next’ command is issued to the server prior to the xover command

Raises:



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/net/nntp.rb', line 158

def xover(groupname=nil, rest=nil)
  raise CommandFailedError, 'No group selected' unless @group || groupname
  if @group.nil?
    group(groupname) 
  elsif groupname.nil?
  else
    @group.name != groupname
    group(groupname)
  end
  debug "Selected Group: #{@group.name}"
  self.next unless rest
  prefix = "xover"
  suffix = numbers_or_id(rest)
  cmd = [prefix, suffix].join ' ' 
  send_cmd(cmd)
  response = nil
  timeout(@response_timeout) do
    response = read_response()
  end
  response
end