#!/bin/awk -f

BEGIN {
	SMB_CONF = "/etc/samba/smb.conf"
	SERVICE = "/sbin/service"
	TESTPARM = "/usr/bin/testparm"
	# split input fields by a colon
	FS=":"
	# set default language
	LANGUAGE="en_US.UTF8"
	# set translation domain
	TEXTDOMAIN = "alterator-samba"
	readmsg=0
	LOGFILE="/var/log/configd.log"
}

# error reporting function
function debug(text, errno) {
	printf "%s " TEXTDOMAIN ": %s: %s\n", strftime("%B %d %H:%M:%S"), text, errno >> LOGFILE
	fflush(LOGFILE)
}

# remove leading and trailing spaces
function trim(arg) {
	gsub(/^[[:space:]]+/,"", arg)
	gsub(/[[:space:]]+$/,"", arg)
	return arg
}

# search a regular expression in a file
function grep(regex, file,		line) {
	while ((error = getline line <file) > 0)
		if (line ~ regex) {
			close(file)
			return 1
		}
	if (error == -1)
		debug("Error reading file '" file "'", ERRNO)
	close(file)
	return 0
}

# get Samba config variable
function samba_read(section, name,	cmd, ret) {
	cmd = TESTPARM " -s --section-name=" section " --parameter-name=\"" name "\" 2> /dev/null"
	cmd | getline ret
	close(cmd)
	return ret
}

# set Samba config variable
function samba_write(section, name, value,	cmd, tempfile, regex1, regex2, error, line) {
        cmd = "mktemp"
        cmd | getline tempfile
        close(cmd)

	regex1 = "^\\[" section "\\]"
	regex2 = "^[[:space:]]*" name "[[:space:]]*="
	while ((error = getline line <SMB_CONF) > 0) {
		if (line ~ regex1) {
			inside = 1
			print line >> tempfile
			print "\t" name " = " value >> tempfile
			continue
		}
		if (!inside || line !~ regex2)
			print line >> tempfile
		if (line ~ /^\[/)
			inside = 0
	}
	if (error == -1)
		debug("Error reading file '" SMB_CONF "'", ERRNO)
	close(SMB_CONF)
	close(tempfile)
	system("cat " tempfile " > " SMB_CONF)
        system("rm -f " tempfile)
}

# remove Samba config variable
function samba_delete(section, name, 	cmd, tempfile, regex1, regex2, error, line, inside) {
        cmd = "mktemp"
        cmd | getline tempfile
        close(cmd)
	regex1 = "^\\[" section "\\]"
	regex2 = "^[[:space:]]*" name "[[:space:]]*="
	while ((error = getline line <SMB_CONF) > 0) {
		if (line ~ regex1) {
			inside = 1
			print line >> tempfile
			continue
		}
		if (!inside || line !~ regex2)
			print line >> tempfile
		if (line ~ /^\[/)
			inside = 0
	}
	if (error == -1)
		debug("Error reading file '" SMB_CONF "'", ERRNO)
	close(SMB_CONF)
	close(tempfile)
	system("cat " tempfile " > " SMB_CONF)
        system("rm -f " tempfile)
}

# rename Samba config section
function samba_rename_section(section, value,	cmd, tempfile, regex, error, line) {
        cmd = "mktemp"
        cmd | getline tempfile
        close(cmd)

	regex = "^\\[" section "\\]"
	while ((error = getline line <SMB_CONF) > 0) {
		if (line ~ regex)
			print "[" value "]" >> tempfile
		else
			print line >> tempfile
	}
	if (error == -1)
		debug("Error reading file '" SMB_CONF "'", ERRNO)
	close(SMB_CONF)
	close(tempfile)
	system("cat " tempfile " > " SMB_CONF)
        system("rm -f " tempfile)
}

# list global Samba settings
function samba_list_global(		cmd, error, line, list) {
	cmd = TESTPARM " -s --section-name=global 2> /dev/null"
	while ((error = cmd | getline line) > 0) {
		if (line ~ /^\[/)
			continue
		if (split(line, list, /=/) > 1) {
			print "(\"" trim(list[1]) "\" param \"" trim(list[1]) "\" value \"" trim(list[2]) "\")"
		}
	}
	if (error == -1)
		debug("Error reading Samba config '" cmd "'", ERRNO)
	close(cmd)
}

# list Samba parameters
function samba_list_params(section,		cmd, error, line, list) {
	cmd = TESTPARM " -sv --section-name=" section "|sort 2> /dev/null"
	while ((error = cmd | getline line) > 0) {
		if (line ~ /^\[/)
			continue
		if (split(line, list, /=/) > 0) {
			print "(\"" trim(list[1]) "\")"
		}
	}
	if (error == -1)
		debug("Error reading Samba config '" cmd "'", ERRNO)
	close(cmd)
}

# list Samba shares
function samba_list_shares(		cmd, error, line, list) {
	cmd = TESTPARM " -s 2> /dev/null"
	while ((error = cmd | getline line) > 0) {
		if (match(line, /^\[([^\]]*)\]/, list))
			if (list[1] != "global")
				print "(\"" list[1] "\" share \"" list[1] "\" path \"" samba_read(list[1], "path") "\")"
	}
	if (error == -1)
		debug("Error reading Samba config '" cmd "'", ERRNO)
	close(cmd)
}

# delete Samba share
function samba_delete_share(section,		cmd, tempfile, error, line, list) {
        cmd = "mktemp"
        cmd | getline tempfile
        close(cmd)

	cmd = TESTPARM " -s 2> /dev/null"
	while ((error = cmd | getline line) > 0)
		if (match(line, /^\[([^\]]*)\]/, list) && list[1] != section)
			system(TESTPARM " -s --section-name=" list[1] " >> " tempfile)
	if (error == -1)
		debug("Error reading Samba config '" cmd "'", ERRNO)
	close(cmd)
	close(tempfile)
	system("cat " tempfile " > " SMB_CONF)
        system("rm -f " tempfile)
}

# show translation
# overwriting locale settings
function N_(text,			list, cmd, line) {
	split(LANGUAGE, list, /:/)
	cmd = "LANGUAGE=\"" LANGUAGE "\" LANG=\"" list[1] ".UTF8\" gettext " TEXTDOMAIN " \"" text "\""
	cmd | getline line
	close(cmd)
	return line
}

# start message reading
/^_message:begin$/ {
	readmsg=1
	next
}

# stop message reading
/^_message:end$/ {
	readmsg=0
	#debug("==========", "==========")
	#for (attribute in params)
	#	debug("params[" attribute "]", params[attribute])
	# overwrite current language
	if (params["language"] != "")
		LANGUAGE = gensub(/;/, ":", "g", params["language"])

	switch (params["action"]) {
		case "constraints":
			print "("
			if (params["type"] == "share")
					printf " share (label \"%s\" required #t match \"^[[:alnum:]]+$\")", N_("Share name")
			printf " param (label \"%s\")", N_("Parameter")
			printf " share (label \"%s\")", N_("Share name")
			printf " comment (label \"%s\")", N_("Comment")
			printf " path (label \"%s\")", N_("Path")
			printf " guestok (label \"%s\")", N_("Guest ok")
			printf " readonly (label \"%s\")", N_("Read only")
			printf " createmask (label \"%s\")", N_("Create mask")
			printf " value (label \"%s\")", N_("Value")
			print ")"
			break
		case "list":
			print "("
			switch (params["_objects"]) {
				case /\yyesno$/:
					print "(\"Yes\" label \"" N_("Yes") "\") (\"No\" label \"" N_("No") "\")"
					break
				case /^global\y/:
					samba_list_global()
					break
				case /^shares\y/:
					samba_list_shares()
					break
				case /^params\y/:
					samba_list_params("global")
					break
			}
			print ")"
			break
		case "read":
			if (match(params["_objects"], /^shares\/(.*)$/, a)) {
				print "("
				print " name \"" a[1] "\""
				print " share \"" a[1] "\""
				print " comment \"" samba_read(a[1], "comment") "\""
				print " path \"" samba_read(a[1], "path") "\""
				print " guestok \"" samba_read(a[1], "guest ok") "\""
				print " readonly \"" samba_read(a[1], "read only") "\""
				print " createmask \"" samba_read(a[1], "create mask") "\""
				print ")"
			}
			else {
				print "("
				print " workgroup \"" samba_read("global", "workgroup") "\""
				print " serverstring \"" samba_read("global", "server string") "\""
				print ")"
			}
			break
		case "write":
			if (match(params["_objects"], /^shares\/(.*)$/, a)) {
				samba_write(a[1], "comment", params["comment"])
				samba_write(a[1], "path", params["path"])
				samba_write(a[1], "guest ok", params["guestok"])
				samba_write(a[1], "read only", params["readonly"])
				samba_write(a[1], "create mask", params["createmask"])
				if (a[1] != params["share"])
						samba_rename_section(a[1], params["share"])
				system(SERVICE " smb reload &> /dev/null")
			}
			if (params["_objects"] == "/") {
					samba_write("global", "workgroup", params["workgroup"])
					samba_write("global", "server string", params["serverstring"])
					system(SERVICE " smb reload &> /dev/null")
			}
			print "()"
			break
		case "new":
			switch (params["type"]) {
				case "global":
					samba_write("global", params["param"], params["value"])
					system(SERVICE " smb reload &> /dev/null")
					print "()"
					break
				case "share":
					if (grep("^\\[" params["share"] "\\]", SMB_CONF)) {
						printf "(error \"%s\")", N_("Such share already exists")
						break
					}
					print "[" params["share"] "]" >> SMB_CONF
					fflush(SMB_CONF)
					system(SERVICE " smb reload &> /dev/null")
					print "()"
					break
				default:
					print "()"
			}
			break
		case "delete":
			switch (params["_objects"]) {
				case /^global\y/:
					match(params["_objects"], /^global\/(.*)$/, a)
					samba_delete("global", a[1])
					system(SERVICE " smb reload &> /dev/null")
					break
				case /^shares\y/:
					match(params["_objects"], /^shares\/(.*)$/, a)
					samba_delete_share(a[1])
					system(SERVICE " smb reload &> /dev/null")
					break
				default:
			}
			print "()"
			break
		default:
			print "#f"
	}
	fflush()
	# delete attribute/value pairs before next cycle
	delete params
	#exit
	next
}

# save attribute/value pairs
{
	if (! readmsg)
		next
	attribute=$1
	value=$2
	# join the rest of fields with a colon
	for (n = 3; n <= NF; n++)
		value=value ":" $n
	value = gensub(/([^\\])\\n/, "\\1\n", "g", value)
	params[attribute]=value
}
