class NNTPError < Exception attr :message def initialize(message) @message = message end end class NNTPSession attr_reader :group, :article, :user, :auth_user_name def initialize(socket, logger) @socket = socket @logger = logger end def write(s) @socket.write s end def putline(line) @socket.write(line.chomp + "\r\n") @logger.debug { "Thread #{Thread.current.id}: > #{line.chomp}" } end # Read a single line from the client and return it. def getline line = @socket.gets("\n").chomp @logger.debug { "Thread #{Thread.current.id}: < #{line}" } return line end # Read a multi-line message from a client. def getarticle # TODO end def close @socket.close end def serve putline "200 server ready" while request = getline.strip cmd, *args = request.split(/\s+/) begin case request when /^LIST$/i write Forum.nntp_grouplist.join("\r\n") + "\r\n" putline '.' when /^LIST OVERVIEW\.FMT$/i write "Subject:\r\nFrom:\r\nDate:\r\nMessage-Id:\r\nReferences:\r\nBytes:\r\nLines:\r\n" putline '.' when /^GROUP (.+)$/i putline select_group($1) when /^AUTHINFO USER (.+)$/i @auth_user_name = $1 @user = nil putline '381 More authentication information required' when /^AUTHINFO PASS (.+)$/i if @auth_user_name # try login @user = User.find_by_login(@auth_user_name, $1) if @user putline '281 Authentication accepted' else putline '502 No permission' end else # password without username putline '482 Authentication rejected' end when /^NEWNEWS/i putline '502 permission denied (command disabled)' when /^SLAVE$/i putline '202 ignored' when /^MODE READER$/i putline '200 ignored' when /^IHAVE/i putline '435 article not wanted - do not send it' when /^QUIT$/i putline '205 closing connection' close return else raise NNTPError, '500 unknown command' end rescue NNTPError => err putline err.message end end end def select_group(name) @group = Forum.find_by_groupname(name) '211 foo' rescue '411 group not found' end end