I now have a working version that handles ATCP negotiations and etc. There are two main problems with Ked's version. 1) His authentication function is wrong (looks like he mixed up some variables) 2) He doesn't parse sub-negotiation options entirely correctly. The code for my version follows. It's cut from part of a larger plugin, so there are some functions and variables that are not defined here. They are all rather self-explanatory however.
The plugin screws up rather quickly when MCCP is active, so it suppresses IAC_WILL_COMPRESS2.
ATCP information is stored in the atcp.values table.
atcp = {}
--code adapted from Ked's ATCP script, which can be found at:
--<http://www.freewebs.com/keldar/atcp.htm>
atcp.IAC = '\255'
atcp.WILL = '\251'
atcp.WONT = '\252'
atcp.ATCP = '\200'
atcp.IAC_SE = '\255\240'
atcp.IAC_SB_ATCP = '\255\250\200'
atcp.IAC_WILL_ATCP = '\255\251\200'
atcp.IAC_WONT_ATCP = '\255\252\200'
atcp.IAC_DO_ATCP = '\255\253\200'
atcp.IAC_DONT_ATCP = '\255\254\200'
atcp.IAC_WILL_COMPRESS2 = '\255\251\086'
atcp.enabled = false
atcp.leftovers = false
atcp.values = {}
atcp.options = {
{name='hello', value=config.atcp_id},
{name='auth', value='1'},
{name='composer', value='1'},
{name='char_name', value='1'},
{name='topvote', value='1'},
{name='char_vitals', value='1'},
{name='room_brief', value='1'},
{name='room_exits', value='1'}
}
--mediapak
--wiz
--filestore
--keepalive
--ATCP FUNCTIONS
function atcp.init()
world.SendPkt(atcp.IAC_DO_ATCP)
local msg = false
for _,option in ipairs(atcp.options) do
if(not msg) then
msg = option.name .. ' ' .. option.value
else
msg = msg .. '\010' .. option.name .. ' ' .. option.value
end
end
world.SendPkt(atcp.IAC_SB_ATCP .. msg .. atcp.IAC_SE .. atcp.IAC_SB_ATCP .. 'login ' .. config.login .. ' ' .. config.password .. atcp.IAC_SE)
end
function atcp.close()
world.SendPkt(atcp.IAC_WONT_ATCP)
end
function atcp.authenticate(seed)
local a = 17
for i=0,string.len(seed) - 1 do
if(math.fmod(i,2) == 0) then
a = a + (string.byte(seed,i + 1) - 96) * (bit.bor(i,13))
else
a = a - (string.byte(seed,i + 1) - 96) * (bit.bor(i,11))
end
end
return a
end
function atcp.retrieve_info(msg,capture)
local ar = {}
local d1 = string.find(msg,' ',0,true) or -2
local d2 = string.find(msg,'\010',0,true) or d1 + 1
if(d2 == -1) then
capture[msg] = {}
atcp.values[msg] = {}
return capture
elseif(d1 < 0) then
d1 = d2 + 1
end
local d
if(d1 < d2) then
ar = utils.split(msg,' ',2)
d = d1
else
ar = utils.split(msg,'\010',2)
d = d2
end
local name = string.sub(msg,0,d - 1)
capture[name] = utils.split(string.sub(msg,d + 1),'\010')
atcp.values[name] = capture[name]
return capture
end
--PARSE FUNCTION
function atcp.parse(packet)
local parsed = {}
if(atcp.leftovers) then
packet = atcp.leftovers .. packet
atcp.leftovers = false
end
--disable mccp
packet = string.gsub(packet, atcp.IAC_WILL_COMPRESS2, '')
packet = string.gsub(packet, atcp.IAC .. '(.)' .. atcp.ATCP,
function(code)
if(code == atcp.WILL) then
if(not atcp.enabled) then
atcp.enabled = true
atcp.init()
if(CTRL_DEBUG) then
system.DebugNote('ATCP PROTOCOL ON.')
end
end
return ''
elseif(code == atcp.WONT) then
if(atcp.enabled) then
atcp.enabled = false
atcp.close()
if(CTRL_DEBUG) then
system.DebugNote('ATCP PROTOCOL OFF.')
end
end
return ''
end
return nil
end)
packet = string.gsub(packet, '' .. atcp.IAC_SB_ATCP .. '(.-)' .. atcp.IAC_SE,
function(msg)
parsed = atcp.retrieve_info(msg,parsed)
return ''
end)
local s,e,msg = string.find(packet, '(\255[^\255]*)$') --"(\255\250?\200?.*[^\255])")
if(s) then
if((#msg == 1) or ((#msg > 1) and string.find(msg, "^\255\250")) or ((#msg > 2) and string.find(msg, "^\255\250\200"))) then
atcp.leftovers = msg
end
end
return packet,parsed
end
--PLUGIN CALLBACKS
function OnPluginPacketReceived(packet)
local packet,parsed = atcp.parse(packet)
if(parsed['Auth.Request']) then
if(parsed['Auth.Request'][1] == 'CH') then
world.SendPkt(atcp.IAC_SB_ATCP .. 'auth ' .. atcp.authenticate(parsed['Auth.Request'][2]) .. ' ' .. config.atcp_id .. atcp.IAC_SE)
if(CTRL_DEBUG) then
system.DebugNote('ATCP AUTHORIZATION SENT.')
end
elseif(parsed['Auth.Request'][1] == 'OFF') then
system.WarningNote('ATCP AUTHORIZATION FAILED.')
elseif(parsed['Auth.Request'][1] == 'ON' and CTRL_DEBUG) then
system.DebugNote('ATCP AUTHORIZATION ACCEPTED.')
end
end
--'Auth.Request'
--'Char.Name'
--'Char.Vitals'
--'Client.Compose'
--'Client.GoodBye'
--'Client.JavaEnv'
--'Client.VoteReminder'
--'Room.Exits'
--'Room.Brief'
return packet
end
|