def process(challenge)
case @stage
when STAGE_ONE
@stage = STAGE_TWO
sparams = {}
c = StringScanner.new(challenge)
while c.scan(/(?:\s*,)?\s*(\w+)=("(?:[^\\"]+|\\.)*"|[^,]+)\s*/)
k, v = c[1], c[2]
if v =~ /^"(.*)"$/
v = $1
if v =~ /,/
v = v.split(',')
end
end
sparams[k] = v
end
raise DataFormatError, "Bad Challenge: '#{challenge}'" unless c.rest.size == 0
raise Error, "Server does not support auth (qop = #{sparams['qop'].join(',')})" unless sparams['qop'].include?("auth")
response = {
:nonce => sparams['nonce'],
:username => @user,
:realm => sparams['realm'],
:cnonce => Digest::MD5.hexdigest("%.15f:%.15f:%d" % [Time.now.to_f, rand, Process.pid.to_s]),
'digest-uri''digest-uri' => 'imap/' + sparams['realm'],
:qop => 'auth',
:maxbuf => 65535,
:nc => "%08d" % nc(sparams['nonce']),
:charset => sparams['charset'],
}
response[:authzid] = @authname unless @authname.nil?
a0 = Digest::MD5.digest( [ response.values_at(:username, :realm), @password ].join(':') )
a1 = [ a0, response.values_at(:nonce,:cnonce) ].join(':')
a1 << ':' + response[:authzid] unless response[:authzid].nil?
a2 = "AUTHENTICATE:" + response['digest-uri''digest-uri']
a2 << ":00000000000000000000000000000000" if response[:qop] and response[:qop] =~ /^auth-(?:conf|int)$/
response[:response] = Digest::MD5.hexdigest(
[
Digest::MD5.hexdigest(a1),
response.values_at(:nonce, :nc, :cnonce, :qop),
Digest::MD5.hexdigest(a2)
].join(':')
)
return response.keys.map { |k| qdval(k.to_s, response[k]) }.join(',')
when STAGE_TWO
@stage = nil
if challenge =~ /rspauth=/
return ''
else
raise ResponseParseError, challenge
end
else
raise ResponseParseError, challenge
end
end