# shroudBNC - an object-oriented framework for IRC
# Copyright (C) 2005 Gunnar Beutner
#
# Script updated KHobbits
#
#  * Allowed the setting of settings on mass for easier rollout.
#  * Fixed locked settings bug and added lockable settings to help file.
#
# Script updated Worrum
#
#  * Updated lockable setting types
#  * Made globallocks set dynamically through /sbnc globallocks
#  * Updated errormessage given to the client, when it tries to set/change a locked setting.
#
# Script updated eteran
#
#  * Removing iface related procedures and bind
#  * Adding iface2 support
#  * minor improvements
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

internalbind command lock:command

# Set default locks, if none ever set before
if {[bncgetglobaltag globallocks] == ""} {
	bncsetglobaltag globallocks "ipv6"
}

# list of settings that might be locked
set ::lockable_settings	[list server port serverpass realname awaynick away awaymessage password appendts quitasaway automodes dropmodes ipv6 timezone ssl vhost]

proc lock:command {client parameters} {
	global lockable_settings

	set command [lindex $parameters 0]

	if {[string equal -nocase $command "help"] && [getbncuser $client admin]} {
		bncaddcommand lock Lock "locks a user's settings" "/sbnc lock <user> \[setting\]\nShows locked settings for a user or locks a setting\nLockable Settings: $lockable_settings"
		bncaddcommand unlock Lock "unlocks a user's settings" "/sbnc unlock <user> <setting>\nUnlocks a users setting"
		bncaddcommand mlock Lock "locks a user setting for all users (KH)" "/sbnc lock <user> \[setting\]\nShows locked settings for users or locks a setting"
		bncaddcommand munlock Lock "unlocks a user setting for all users (KH)" "/sbnc unlock <user> <setting>\nUnlocks a user setting"
		bncaddcommand globallocks Lock "set globallocks which are applied for all users" "/sbnc globallocks \[lock1 lock2 lockn / none\]\nSet locks which are globally applied (for all users). none unsets all locks."
	}

	if {[string equal -nocase $command "lock"]} {
		if {[getbncuser $client admin]} {
			if {[llength $parameters] <= 1} {
				bncreply "Syntax: /sbnc lock <user> \[setting\]"
				haltoutput
			} else {
				if {[string equal -nocase [lindex $parameters 2] ""]} {
					set tmp [split [bncuserlist] " "]
					set res [lsearch $tmp [lindex $parameters 1]]
					if {[string equal -nocase $res "-1"]} {
						bncreply "No such user [lindex $parameters 1]."
						haltoutput
					} else {
						set tmp [split [getbncuser [lindex $parameters 1] tag locksetting] ","]
						bncreply "Locked settings for user [lindex $parameters 1]:"
						if {[string equal -nocase $tmp ""]} {
							bncreply "None."
							haltoutput
						} else {
							bncreply $tmp
							haltoutput
						}
					}
				} else {
					if {[lsearch -exact $lockable_settings [lindex $parameters 2]] == -1} {
						bncreply "Error: Cannot lock this setting."
						haltoutput
					} else {
						set tmp [split [getbncuser [lindex $parameters 1] tag locksetting] ","]
						lappend tmp [lindex $parameters 2]
						setbncuser [lindex $parameters 1] tag locksetting [join $tmp ","]
						bncreply "Done."
						haltoutput
					}
				}
			}
		}
	}

	if {[string equal -nocase $command "mlock"]} {

		if {[getbncuser $client admin]} {
			if {[llength $parameters] <= 0} {
				bncreply "Syntax: /sbnc mlock \[setting\]"
				haltoutput
			} else {
				if {[string equal -nocase [lindex $parameters 1] ""]} {
					foreach user [bncuserlist] {
						set tmp [split [getbncuser $user tag locksetting] ","]
						if {[string equal -nocase $tmp ""]} {
							bncreply "Locked settings for $user: None."
							haltoutput
						} else {
							bncreply "Locked settings for $user: $tmp"
							haltoutput
						}
					}
				} else {
					if {[lsearch -exact $lockable_settings [lindex $parameters 1]] == -1} {
						bncreply "Error: Cannot lock this setting."
						haltoutput
					} else {
						foreach user [bncuserlist] {
							set tmp [split [getbncuser $user tag locksetting] ","]
							lappend tmp [lindex $parameters 1]
							setbncuser $user tag locksetting [join $tmp ","]
						}
						bncreply "Done."
						haltoutput
					}
				}
			}
		}

	}


	if {[string equal -nocase $command "unlock"]} {
		if {[getbncuser $client admin]} {
			if {[llength $parameters] < 3} {
				bncreply "Syntax: /sbnc unlock <user> <setting>"
				haltoutput
			} else {
				set tmp [split [bncuserlist] " "]
				set res [lsearch $tmp [lindex $parameters 1]]
				if {[string equal -nocase $res "-1"]} {
					bncreply "No such user [lindex $parameters 1]."
					haltoutput
				} else {
					set tmp [split [getbncuser [lindex $parameters 1] tag locksetting] ","];
					set idx [lsearch -exact $tmp [lindex $parameters 2]]
					set tmp [lreplace $tmp $idx $idx]
					setbncuser [lindex $parameters 1] tag locksetting [join $tmp ","]
					bncreply "Done."
					haltoutput
				}
			}
		}
	}

	if {[string equal -nocase $command "munlock"]} {
		if {[getbncuser $client admin]} {
			if {[llength $parameters] < 2} {
				bncreply "Syntax: /sbnc munlock <setting>"
				haltoutput
			} else {
				foreach user [bncuserlist] {
					set tmp [split [getbncuser $user tag locksetting] ","];
					set idx [lsearch -exact $tmp [lindex $parameters 1]]
					set tmp [lreplace $tmp $idx $idx]
					setbncuser $user tag locksetting [join $tmp ","]
				}
				bncreply "Done."
				haltoutput
			}
		}
	}

	if {[string equal -nocase $command "globallocks"]} {
		if {[getbncuser $client admin]} {
			if {[llength $parameters] < 2} {
				bncreply "Current globallocks: [bncgetglobaltag globallocks]"
				bncreply "Syntax: /sbnc globallocks \[lock1 lock2 lockn / none\]"
				haltoutput
			} elseif { [lindex $parameters 1] == "none" } {
				bncsetglobaltag globallocks ""
				bncreply Done.
				haltoutput
			} else {
				set settings [lrange $parameters 1 end]
				foreach setting $settings {
					if {[lsearch -exact $lockable_settings $setting] == -1} {
						bncreply "Error: $setting: Cannot lock this setting."
						haltoutput
						return
					}
				}
				bncsetglobaltag globallocks $settings
				bncreply Done.
				haltoutput
			}
		}
	}

	if {[string equal -nocase $command "set"] && [llength $parameters] > 2} {
		set setting [lindex $parameters 1]
		set notlocked [lock:set $client $setting [join [lrange $parameters 2 end]]]

		if {[string equal -nocase $setting "server"] && $notlocked} {
			set notlocked [lock:set $client "port" [join [lrange $parameters 2 end]]]
		}

		if {$notlocked} {
			return
		} else {
			bncreply "Error: You cannot modify this setting. This setting has been locked by your admin."
			haltoutput
		}
	}

}

proc lock:islocked {account setting} {

	set tmp [split [getbncuser $account tag locksetting] ","]

	if {[lsearch -exact $tmp $setting] != -1} {
		return 1
	} elseif {[lsearch -exact [bncgetglobaltag globallocks] $setting] != -1} {
		return 2
	} else {
		return 0
	}
}

# account = who wants to set
# parameters
#	0 = what user
#	1 = what setting
#	2 - end = value
# returns:
#	1 if user can change the setting
#	0 otherwise
proc lock:set {account setting value} {
	if {[getbncuser $account admin]} {
		return 1
	} elseif {![string equal [lock:islocked $account $setting] "0"]} {
		return 0
	} else {
		return 1
	}
}

proc iface-lock:lock_get {} {
        set locks [split [getbncuser [getctx] tag locksetting] ","]

        return [itype_list_strings [join $locks]]
}

proc iface-lock:lock_get_global {} {
        return [itype_list_strings [join [bncgetglobaltag "globallocks"]]]
}

proc iface-lock:lock_add {username setting} {
		global lockable_settings

		if {[lsearch -exact $lockable_settings $setting] == -1} {
			return [itype_exception "RPC_ERROR Unknown Setting."]
		}

        set locks [split [getbncuser $username tag locksetting] ","]
        lappend locks [string tolower $setting]
        setbncuser $username tag locksetting [join $locks ","]

        return ""
}

proc iface-lock:lock_add_global {setting} {
		global lockable_settings

		if {[lsearch -exact $lockable_settings $setting] == -1} {
			return [itype_exception "RPC_ERROR Unknown Setting."]
		}

		set locks [split [bncgetglobaltag "globallocks"]]
		lappend locks [string tolower $setting]
		bncsetglobaltag "globallocks" [join $locks]

		return ""
}

proc iface-lock:lock_remove {username setting} {
		global lockable_settings

		if {[lsearch -exact $lockable_settings $setting] == -1} {
			return [itype_exception "RPC_ERROR Unknown Setting."]
		}

        set locks [split [getbncuser $username tag locksetting] ","]
        set index [lsearch -exact $locks [string tolower $setting]]

        if {$index > -1} {
        	set locks [lreplace $locks $index $index]
        }

        setbncuser $username tag locksetting [join $locks ","]

        return ""
}

proc iface-lock:lock_remove_global {setting} {
		global lockable_settings

		if {[lsearch -exact $lockable_settings $setting] == -1} {
			return [itype_exception "RPC_ERROR Unknown Setting."]
		}

        set locks [split [bncgetglobaltag "globallocks"]]
        set index [lsearch -exact $locks [string tolower $setting]]

        if {$index > -1} {
        	set locks [lreplace $locks $index $index]
        }

        bncsetglobaltag "globallocks" [join $locks]

        return ""
}

if {[info commands "registerifacecmd"] != ""} {
        registerifacecmd "lock" "lock_get" "iface-lock:lock_get"
        registerifacecmd "lock" "lock_get_global" "iface-lock:lock_get_global"
        registerifacecmd "lock" "lock_add" "iface-lock:lock_add" "access:admin"
        registerifacecmd "lock" "lock_add_global" "iface-lock:lock_add_global" "access:admin"
        registerifacecmd "lock" "lock_remove" "iface-lock:lock_remove" "access:admin"
        registerifacecmd "lock" "lock_remove_global" "iface-lock:lock_remove_global" "access:admin"
}