#! /usr/bin/env lua5.1
-- 
-- Released under the terms of GPLv3 or at your option any later version.
-- No warranties.
-- Copyright 2009 Enrico Tassi <gares@fettunta.org>

require 'syncmaildir'

for k,v in pairs(syncmaildir) do _G[k] = v end

-- ============================= MAIN =====================================

function main()
	if arg[1] == '-v' then
		set_verbose(true)
		table.remove(arg,1)
	end
	
	if #arg < 2 then
		io.stderr:write([[
Usage: ]]..arg[0]..[[ [-v] endpointname mailboxes...]],'\n')
		os.exit(1)
	end
	
	local endpoint = arg[1]
	table.remove(arg,1)
	local dbfile = dbfile_name(endpoint, arg)
	local xdelta = dbfile .. '.xdelta'
	local newdb = dbfile .. '.new'

	local database_opt = '--db-file '.. dbfile
	local mailbox_opt = table.concat(arg,' ')

	-- we check the protocol version and dbfile fingerprint
	handshake(dbfile)
	
	-- run mddiff and send the output to the client
	local mddiff = MDDIFF..database_opt..' '..mailbox_opt
	log('checking '.. MDDIFF)
	if os.execute('test -e '..MDDIFF) ~= 0 then
		log_error('Cannot execute '..MDDIFF,'\n')
		os.exit(4)
	end
	log('calling '.. mddiff)
	local r = io.popen(mddiff,"r")
	local sent = 0
	while true do
		local l = r:read("*l")
		if l ~= nil then
			sent = sent + 1
			io.write(l,'\n')
		else
			break
		end
	end
	r:close()
	log('done\n')
	
	
	-- end the first phase, now the client should
	-- apply the diff eventually asking for the transmission
	-- of some data
	io.write('END\n')
	io.flush()
	
	-- process client commands
	while true do
		local l = io.read('*l')
		if l == nil then 
			-- end of input stream, client is dead
			log_error('Communication with client died unexpectedly\n')
			os.exit(3)
		end
		if l:match('^COMMIT$') then
			-- the client applied the diff, the new mailbox
			-- fingerprint should be used for the next sync
			local rc
			rc = os.execute('xdelta delta '..dbfile..' '..newdb..' '..xdelta)
			if rc ~= 0 and rc ~= 256 then
				log_error('Failed running `xdelta delta` on db file: '..rc)
				os.exit(1)
			end
			transmit(io.stdout, xdelta, "all")
			os.remove(xdelta)
		elseif l:match('^DONE$') then
			os.rename(newdb, dbfile) 
			os.exit(0)
		elseif l:match('^ABORT$') then
			-- the client failed in applying the diff
			log_error('Client aborted, removing '..dbfile..'.new\n')
			os.remove(dbfile..".new")
			os.exit(2)
		elseif l:match('^GET ') then
			local path = l:match('^GET ([^%s]+)$')
			transmit(io.stdout, path, "all")
		elseif l:match('^GETHEADER ') then
			local path = l:match('^GETHEADER ([^%s]+)$')
			transmit(io.stdout, path, "header")
		elseif l:match('^GETBODY ') then
			local path = l:match('^GETBODY ([^%s]+)$')
			transmit(io.stdout, path, "body")
		else
			-- protocol error
			log_error('Invalid command '..l..'\n')
			os.exit(1)
		end
	end
end

set_strict()

xpcall(main,function(msg)
	log_error(tostring(msg))
	os.exit(1)
end)

-- vim:set ts=4:
