<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>

<muclient>
<plugin
   name="ATCP"
   author="Keldar"
   id="a2a6350d9144c09a8a7c4636"
   language="Lua"
   purpose="Enabling the ATCP protocol"
   date_written="2006-10-15"
   requires="4.00"
   version="1.5"
   >
<description trim="y">
<![CDATA[

BUG: If the closing code is split between two packets,
the plugin fails to catch it.

This plugin enables the use of ATCP in Mushclient.

It utilizes the FLC package (if available) to store
information about your current vital statistics and
location.

WARNING: ATCP has been reported to fail when working
alongside MCCP. Therefore to use ATCP you are advised
to disable MCCP compression.

In order to access ATCP data from your own Lua scripts
you can use the following FLC functions:

klib.GetRoomName()  -- returns the name of the current room
klib.GetRoomExits() -- returns a list of currrent exits

katcp.GetVitals()   -- returns a table with the following
                    -- fields:
                    -- curr_health
                    -- curr_mana
                    -- curr_end
                    -- curr_will
                    -- max_health
                    -- max_mana
                    -- max_end
                    -- max_will
                    -- nl          (% to next level)
]]>
</description>

</plugin>

<triggers>
  <trigger
   enabled="y"
   lines_to_match="7"
   match="\n\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\n   You are using an unsupported version of the client software\.\n\n   Please update by forcing a reload of the page and reconnect\.\n\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\n\Z"
   multi_line="y"
   name="unsup_message"
   regexp="y"
   script="GagUnsup"
   sequence="100"
  >
  </trigger>
</triggers>

<aliases>
  <alias
   match="^\s*debug\s+(on|off)\s*$"
   enabled="y"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>if "%1" == "on" then
  DEBUG = true
else
  DEBUG = false
end</send>
  </alias>
</aliases>



<!--  Get our standard constants -->


<!--  Script  -->


<script>
<![CDATA[
require "tprint"

pcall (require, "flc.katcp")

pcall (require, "flc.kutils")

function DoNote(msg)
  if kutils then
    kutils.DoNote(msg)
  else
    Note(msg)
  end
end

client_id =  "Muclient ".. Version()

nexus_opts = {
{"hello", client_id},
{"auth", "1"},
--{"composer", "1"},
--{"keepalive", "1"},
{"char_name", "1"},
--{"filestore", "1"},
--{"topvote", "1"},
{"char_vitals", "1"},
{"room_brief", "1"},
{"room_exits", "1"},
--{"mediapak", "1"},
--{"wiz", "1"}
}


codes = {
IAC_WILL_ATCP = "\255\251\200",
IAC_WONT_ATCP = "\255\252\200",
IAC_DO_ATCP = "\255\253\200",
IAC_DONT_ATCP = "\255\254\200",
IAC_SB_ATCP = "\255\250\200",
IAC_SE = "\255\240",
IAC_DO_EOR = "\255\253\025",
IAC_WILL_EOR = "\255\251\025",
IAC_GA = "\255\249"
}

leftovers = ""


PAT = codes.IAC_SB_ATCP .. "(.-)" .. codes.IAC_SE

function SendATCP(msg)
  SendPkt(codes.IAC_SB_ATCP .. msg .. codes.IAC_SE)
end

if GetInfo(106) then
  connected = false
else
  connected = true
end

send_buffer = {}
function OnPluginSend(data)
  if connected then
    return true
  else
    table.insert(send_buffer, data)
    return false
  end
    
end

function OnPluginConnect()
  local msg = ""
  for _,v in ipairs(nexus_opts) do
    msg = msg .. v[1] .. " " .. v[2] .. "\10"
  end 
  msg = string.sub(msg, 1, -2)
  SendPkt(codes.IAC_DO_ATCP .. codes.IAC_SB_ATCP .. msg .. codes.IAC_SE)
  connected = true
  for _,comm in ipairs(send_buffer) do
    Send(comm)
  end
  send_buffer = {}
end

function OnPluginDisconnect()
  connected = false
end

function OnPluginPacketReceived(packet)
	local orig_packet = packet
  if string.find(packet, codes.IAC_WILL_ATCP) then
    DoNote("ATCP enabled.")
    packet = string.gsub(packet, "(.-)" .. codes.IAC_WILL_ATCP .. "(.-)", "%1%2")
    if katcp then katcp.SetATCP(true) end
  end
  if string.find(packet, codes.IAC_WONT_ATCP) then
    DoNote("ATCP disabled.")
    if katcp then katcp.SetATCP(false) end
  end
  if string.find(packet, codes.IAC_WILL_EOR) then
    packet = string.gsub(packet, "(.-)" .. codes.IAC_WILL_EOR .. "(.-)", "%1%2")
  end
  local packet, atcp, parsed = parseATCP(packet)
  if parsed["Auth.Request CH"] then
    SendATCP("auth " .. tostring(atcp_auth(parsed["Auth.Request CH"])) .. " " .. client_id)
  end
  if parsed["Auth.Request ON"] then
    DoNote("Authorization accepted.")
  end
  --local start = GetInfo(232)
  if katcp then
  	if parsed["Char.Vitals"] ~= nil then
    	katcp.SetVitals(parsed["Char.Vitals"])
    end
    if parsed["Room.Brief"] ~= nil then
    	katcp.SetRoomName(parsed["Room.Brief"])
    end
    if parsed["Room.Exits"] ~= nil then
    	katcp.SetRoomExits(parsed["Room.Exits"])
    end
  end
  --AppendToNotepad("test", tostring(GetInfo(232) - start) .. "\r\n")
  
  if DEBUG then
  	AppendToNotepad("ATCP", "[OnPluginPacketReceived]\r\n  Incoming: " .. orig_packet .. "\r\n  Outgoing: " .. packet .. "\r\n")
  end
  return packet
end

function get_room(msg, tab)
  local s,e,what,cont = string.find(msg, "^(Room%.%w+) (.-)$")
  if s then
    tab[what] = cont
    return tab
  else 
    return nil
  end
end

STATES = {}
STATES.waiting = 0
STATES.open = 1
STATES.closed = 2

state = STATES.waiting

function parseATCP2(packet)
	local packet = packet
	local s,e,prev,msg,nxt,asplit
	local atcp, parsed = {}, {}
	
end 

function parseATCP(packet)
  local packet = packet
  local s,e,prev,msg,nxt, asplit
  local atcp,parsed = {}, {}
  if #leftovers > 0 then
  
    s,e,msg = string.find(leftovers .. packet, "^" .. PAT)--codes.IAC_SB_ATCP .. "(.-)" .. codes.IAC_SE)
    if s then
      local ret = get_room(msg, parsed)
      if not ret then
        asplit = utils.split(msg, "\10")
        parsed[asplit[1] ] = asplit[2]
      else
        parsed = ret
      end
      table.insert(atcp, msg)
      packet = string.sub(leftovers .. packet, e+1)
      leftovers = ""
    --elseif (string.find(leftovers .. packet, "^\255\250") ~= nil) then
    --	leftovers = leftovers .. packet
    --	return "", atcp, parsed
    elseif (leftovers == "\255") and (string.sub(packet, 1,1) ~= "\255") then
    	packet = leftovers .. packet
    	leftovers = ""
    else
    	leftovers = ""
    end

  end
  
  local new_packet = ""
  local pat2 = PAT
  new_packet = string.gsub(packet, pat2, function(msg)
    local ret = get_room(msg, parsed)
    if not ret then
      asplit = utils.split(msg, "\10")
      parsed[asplit[1] ] = asplit[2] or ""
    else
      parsed = ret
    end
    table.insert(atcp, msg)
    return ""
  end)
  
  local s,e,msg
  s,e,msg = string.find(new_packet, "(\255[^\255]*)$")--"(\255\250?\200?.*[^\255])")
  if s then
    if (#msg == 1) or ( (#msg > 2) and string.find(msg, "^\255\250\200") ) 
      or( (#msg > 1) and string.find(msg, "^\255\250") ) then --[^\251\252\253\254\240]") ) then
      leftovers = msg
      new_packet = string.sub(new_packet, 1, s-1)
    end
  end
  
  packet = new_packet
 
  
  return packet, atcp, parsed
end

function GagUnsup(n,o,w)
  DeleteLines(6)
end


function atcp_auth(seed)
  local a,i = 17, 0
  local n
  
  for letter in string.gmatch(seed, ".") do
    n = string.byte(letter) - 96
    
    if math.fmod(i, 2) == 0 then
      a = a + n * (bit.bor(i, 13))
    else
      a = a - n * ( bit.bor(i, 11))
    end
    
    i = i + 1
  end
  
  return a
end

tests_tab = {

}

function run_tests()
	print ("Running tests for plugin ATCP")
    for i,v in ipairs(tests_tab) do
    	terminated = false
        print (i, "=", v())
    end
end

--run_tests()


]]>
</script>


<!--  Plugin help  -->

<aliases>
  <alias
   script="OnHelp"
   match="ATCP:help"
   enabled="y"
  >
  </alias>
</aliases>

<script>
<![CDATA[
function OnHelp ()
  world.Note (world.GetPluginInfo (world.GetPluginID (), 3))
end
]]>
</script> 

</muclient>
