# Offline logging for sbnc by Worrum
# Script edited by KHobbits, changes tracked at http://khobbits.net/sbnc/
# Questions, remarks, suggestions: join #sbnc
# Clientside options settable through /sbnc set
# This version is for 1.2!
internalbind svrlogon log:redetach
internalbind attach log:attach
internalbind detach log:detach
internalbind command log:settings
if {[bncgetglobaltag chanlog] == ""} {
	bncsetglobaltag chanlog "privmsg,notice,join,part,kick,quit,nick,topic,mode"
}

proc log:settings {client parameters} {
	if {[string equal -nocase [lindex $parameters 0] "set"]} {
		if {[string equal -nocase [lindex $parameters 1] "offlinelog"]} {
			if {[string equal [lindex $parameters 2] ""]} {
				bncreply "Syntax: /sbnc set offlinelog on/off"
				bncreply "This setting enables the logging of all channels, the logs will be played back on connect if the method is left to automatic."
				if {[string equal -nocase [getbncuser $client tag offlinelog] ""]} {
					bncreply "Current value: off"
				} else  {
					bncreply "Current value: [getbncuser $client tag offlinelog]"
				}
				haltoutput
				return
			} elseif {![string equal -nocase [lindex $parameters 2] "on"] && ![string equal -nocase [lindex $parameters  2] "off"]} {
				bncreply "Value should be either on or off."
				haltoutput

				return
			} else {
				if {[string equal -nocase [lindex $parameters 2] "off"]} {
					setbncuser $client tag offlinelog
					bncreply "Done."
					haltoutput
					return
				}
				setbncuser $client tag offlinelog [string tolower [lindex $parameters 2]]
				bncreply "Done."
				haltoutput
			}
		} elseif {[string equal -nocase [lindex $parameters 1] "offlinelog.method"]} {
			if {[string equal [lindex $parameters 2] ""]} {
				bncreply "Syntax: /sbnc set offlinelog.method auto/query"
				bncreply "Auto: logs are played automatically. Query: manual trigger with query based warning."
				if {[string equal -nocase [getbncuser $client tag offlinelog.method] ""]} {
					bncreply "Current value: auto"
				} else  {
					bncreply "Current value: [getbncuser $client tag offlinelog.method]"
				}
				haltoutput
				return
			} elseif {![string equal -nocase [lindex $parameters 2] "auto"] && ![string equal -nocase [lindex $parameters  2] "query"]} {
				bncreply "Value should be either auto or query."
				haltoutput
				return
			} else {
				setbncuser $client tag offlinelog.method [lindex $parameters 2]
				bncreply "Done."
				haltoutput
			}
		} elseif {[string equal -nocase [lindex $parameters 1] "offlinelog.exclude"]} {
			if {[string equal [lindex $parameters 2] ""]} {
				bncreply "Syntax: /sbnc set offlinelog.exclude #channel1,#channel2,#channel3 or none to unset it"
				bncreply "Channels added to this list won't be logged.  Use this to except channels like #msl or #irchelp to save log space and reduce BNC lag."
				if {[string equal -nocase [getbncuser $client tag offlinelog.exclude] ""]} {
					bncreply "Current value: none"
				} else  {
					bncreply "Current value: [getbncuser $client tag offlinelog.exclude]"
				}
				haltoutput
				return
			} else {
				if {!([string equal -nocase [lindex $parameters 3] ""])} {
					bncreply "One of the settings you supplied are incorrect, or wrong syntax used."
					bncreply "Syntax: offlinelog.exclude #channel1,#channel2,#channel3"
					bncreply "Valid options are: [join [internalchannels] , ],none"
					haltoutput
					return
				}
				if {[string equal -nocase [lindex $parameters 2] "none"]} {
					setbncuser $client tag offlinelog.exclude
					bncreply "Done."
					haltoutput
					return
				}
				setbncuser $client tag offlinelog.exclude [string tolower [lindex $parameters 2]]
				bncreply "Done."
				haltoutput
			}
		} elseif {[string equal -nocase [lindex $parameters 1] "offlinelog.options"]} {
			if {[string equal [lindex $parameters 2] ""]} {
				bncreply "Syntax: /sbnc set offlinelog.options option1,option2,option3"
				bncreply "Valid options are: [bncgetglobaltag chanlog] or reset."
				if {[string equal -nocase [getbncuser $client tag offlinelog.options] ""]} {
					bncreply "Current value: [bncgetglobaltag chanlog]"
				} else  {
					bncreply "Current value: [getbncuser $client tag offlinelog.options]"
				}
				haltoutput
				return
			} else {
				foreach item [split [lindex $parameters 2] ,] {
					if {[lsearch -exact [split [list [bncgetglobaltag chanlog],reset] ,] [string tolower $item]] == -1  || !([string equal -nocase [lindex $parameters 3] ""])} {
						bncreply "One of the settings you supplied are incorrect or wrong syntax used."
						bncreply "Syntax: offlinelog.options option1,option2,option3 or reset."
						bncreply "Valid options are: [bncgetglobaltag chanlog],reset"
						haltoutput
						return
					}
				}
				if {[string equal -nocase [lindex $parameters 2] "reset"]} {
					setbncuser $client tag offlinelog.options
					bncreply "Done."
					haltoutput
					return
				}
				setbncuser $client tag offlinelog.options [string tolower [lindex $parameters 2]]
				bncreply "Done."
				haltoutput
			}
		} elseif {[string equal [lindex $parameters 1] ""]} {
			if {[string equal -nocase [getbncuser $client tag offlinelog] ""]} {
				utimer 0 [list bncreply "offlinelog - off"]
			} else  {
				utimer 0 [list bncreply "offlinelog - [getbncuser $client tag offlinelog]"]
			}
			if {[string equal -nocase [getbncuser $client tag offlinelog.method] ""]} {
				utimer 0 [list bncreply "offlinelog.method - Auto"]
			} else  {
				utimer 0 [list bncreply "offlinelog.method - [getbncuser $client tag offlinelog.method]"]
			}
			if {[string equal -nocase [getbncuser $client tag offlinelog.exclude] ""]} {
				utimer 0 [list bncreply "offlinelog.exclude - None set"]
			} else  {
				utimer 0 [list bncreply "offlinelog.exclude - [getbncuser $client tag offlinelog.exclude]"]
			}
			if {[string equal -nocase [getbncuser $client tag offlinelog.options] ""]} {
				utimer 0 [list bncreply "offlinelog.options - [bncgetglobaltag chanlog]"]
			} else  {
				utimer 0 [list bncreply "offlinelog.options - [getbncuser $client tag offlinelog.options]"]
			}
		}
	}
	if {[string equal [lindex $parameters 0] "unset"]} {
		if {[string equal -nocase [lindex $parameters 1] "offlinelog"]} {
			setbncuser $client tag offlinelog
			bncreply "Done."
			haltoutput
		}
		if {[string equal -nocase [lindex $parameters 1] "offlinelog.method"]} {
			setbncuser $client tag offlinelog.method
			bncreply "Done."
			haltoutput
		}
		if {[string equal -nocase [lindex $parameters 1] "offlinelog.exclude"]} {
			setbncuser $client tag offlinelog.exclude
			bncreply "Done."
			haltoutput
		}
		if {[string equal -nocase [lindex $parameters 1] "offlinelog.options"]} {
			setbncuser $client tag offlinelog.options
			bncreply "Done."
			haltoutput
		}
	}
	if {[string equal -nocase [lindex $parameters 0] "playlog"]} {
		if {![file exists users/$client.clog]} {
			bncreply "Your channel log is empty. Type '/sbnc help playlog' for help with this feature."
		} else {
			log:playlog $client
			bncreply "Done."
		}
		haltoutput
	}
	if {[string equal -nocase [lindex $parameters 0] "eraselog"]} {
		if {![file exists users/$client.clog]} {
			bncreply "Your channel log is empty. Type '/sbnc help eraselog' for help with this feature."
		} else {
			file delete "users/$client.clog"
			bncreply "Done."
		}
		haltoutput
	}
	if {[string equal -nocase [lindex $parameters 0] "logwhat"] && [getbncuser [getctx] admin]} {
		if {[string equal [lindex $parameters 1] ""]} {
			bncreply "Current value: [bncgetglobaltag chanlog]"
			bncreply "For help type : /msg -sbnc help logwhat"
			haltoutput
			return
		} else  {
			foreach item [split [lindex $parameters 1] ,] {
				if {[lsearch -exact [list none privmsg notice join part kick quit nick topic mode] [string tolower $item]] == -1  || !([string equal -nocase [lindex $parameters 2] ""])} {
					bncreply "One of the settings you supplied are incorrect or wrong syntax used."
					bncreply "Syntax: /sbnc logwhat option1,option2,option3"
					bncreply "Valid options are: none (log nothing), privmsg, notice, join* , part, kick, quit*, nick*, topic, mode.   *: Can be VERY spammy"
					haltoutput
					return
				}
			}
			bncsetglobaltag chanlog [string tolower [lindex $parameters 1]]
			bncreply "Done."
			haltoutput
		}
	}
	if {[string equal -nocase [lindex $parameters 0] "help"]} {
		set omghelp "You can exclude channels and control what is logged from /sbnc set.\nIf you set offlinelog.method to query, you will be warned you have logs to review instead of the logs playing automatically on connect."
		bncaddcommand playlog KHUser "plays your channel logs (if available)" "Play's your channel logs.\n$omghelp\nNote: Gets auto-erased after being played"
		bncaddcommand eraselog KHUser "erases your channel logs (if available)" "Erase your channel logs if you aren't interested in them.\n$omghelp"
		if {[getbncuser [getctx] admin]} {
			bncaddcommand logwhat KHAdmin "set logging options" "Tell sbnc what to log for all clients \nSyntax: /sbnc logwhat option1,option2,option3 \nValid options are: none (log nothing), privmsg, notice, join* , part, kick, quit*, nick*, topic, mode.   *: Can be VERY spammy"
		}
	}
}

proc log:attach {client} {
	internalunbind server log:pubm PRIVMSG $client
	internalunbind server log:notc NOTICE $client
	internalunbind server log:join JOIN $client
	internalunbind server log:part PART $client
	internalunbind server log:sign QUIT $client
	internalunbind server log:kick KICK $client
	internalunbind server log:topic TOPIC $client
	internalunbind server log:nick NICK $client
	internalunbind server log:mode MODE $client
	if {[file exists users/$client.clog]} {
		if {[string equal -nocase [getbncuser $client tag offlinelog.method] "query"]} {
			setctx $client
			bncreply "You have new channel messages. Use '/msg -sBNC playlog' to view them."
			return
		} else  {
			utimer 5 [list log:playlog $client]
		}
	}
}

proc log:redetach {client} {
	log:detach $client
}

proc log:detach {client} {
	if {[getbncuser $client hasclient] || [string equal -nocase [getbncuser $client tag offlinelog] ""] || [string equal -nocase [bncgetglobaltag chanlog] "none"]} {return "Client attached, or none/off set"}
	set x [split [getbncuser $client tag offlinelog.options] ,]
	if {[string equal -nocase $x ""]} {
		set x [split [bncgetglobaltag chanlog] ,]
	}
	if {!([lsearch -exact $x "privmsg"] == -1)} {
		internalbind server log:pubm PRIVMSG $client
	}
	if {!([lsearch -exact $x "notice"] == -1)} {
		internalbind server log:notc NOTICE $client
	}
	if {!([lsearch -exact $x "join"] == -1)} {
		internalbind server log:join JOIN $client
	}
	if {!([lsearch -exact $x "part"] == -1)} {
		internalbind server log:part PART $client
	}
	if {!([lsearch -exact $x "quit"] == -1)} {
		internalbind server log:sign QUIT $client
	}
	if {!([lsearch -exact $x "kick"] == -1)} {
		internalbind server log:kick KICK $client
	}
	if {!([lsearch -exact $x "topic"] == -1)} {
		internalbind server log:topic TOPIC $client
	}
	if {!([lsearch -exact $x "nick"] == -1)} {
		internalbind server log:nick NICK $client
	}
	if {!([lsearch -exact $x "mode"] == -1)} {
		internalbind server log:mode MODE $client
	}
	putmainlog "Starting offline log for $client"
}

proc log:pubm {client arg} {
	if {![string equal -nocase [lindex $arg 1] "PRIVMSG"] || !([lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower [lindex $arg 2]]] == -1) || [isbotnick [lindex [split [lindex $arg 0] !] 0]]} {return exclude}
	if {[regexp "^\001ACTION (.*?)\001$" [lindex $arg 3] foo text]} {
		log:everything $client [lindex $arg 2] "\[[log:time $client]\]:\00306 *[lindex [split [lindex $arg 0] !] 0]* [lrange [lindex $arg 3] 1 end] \017\00306*"
	} else  {
		log:everything $client [lindex $arg 2] "\[[log:time $client]\]:\00304 <[lindex [split [lindex $arg 0] !] 0]>\003 [lindex $arg 3]"
	}
	haltoutput
}

proc log:notc {client arg} {
	if {![string equal -nocase [lindex $arg 1] "NOTICE"] || !([lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower [lindex $arg 2]]] == -1) || [isbotnick [lindex [split [lindex $arg 0] !] 0]]} {return exclude}
	log:everything $client [lindex $arg 2] "\[[log:time $client]\]:\00305 -[lindex [split [lindex $arg 0] !] 0]- [lindex $arg 3]"
	haltoutput
}

proc log:join {client arg} {
	if {![string equal -nocase [lindex $arg 1] "JOIN"] || !([lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower [lindex $arg 2]]] == -1)} {return exclude}
	log:everything $client [lindex $arg 2] "\[[log:time $client]\]:\00310 [lindex $arg 0] joined [lindex $arg 2]"
}

proc log:part {client arg} {
	if {![string equal -nocase [lindex $arg 1] "PART"] || !([lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower [lindex $arg 2]]] == -1)} {return exclude}
	log:everything $client [lindex $arg 2] "\[[log:time $client]\]:\00314 [lindex $arg 0] parted [lindex $arg 2] ([lindex $arg 3]\017\00314)"
}

proc log:sign {client arg} {
	if {![string equal -nocase [lindex $arg 1] "QUIT"]} {return exclude}
	setctx $client
	foreach chan [internalchannels] {
		if {[lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower $chan]] == -1} {
			if {[onchan [lindex [split [lindex $arg 0] !] 0] $chan]} {
				log:everything $client $chan "\[[log:time $client]\]:\00302 [lindex $arg 0] Quit ([lindex $arg 2]\017\00302)"
			}
		}
	}
}

proc log:kick {client arg} {
	if {![string equal -nocase [lindex $arg 1] "KICK"] || !([lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower [lindex $arg 2]]] == -1)} {return exclude}
	log:everything $client [lindex $arg 2] "\[[log:time $client]\]:\00310 [lindex $arg 0] Kicked [lindex $arg 3] ([lindex $arg 4]\017\00310)"
}

proc log:topic {client arg} {
	if {![string equal -nocase [lindex $arg 1] "TOPIC"] || !([lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower [lindex $arg 2]]] == -1)} {return exclude}
	log:everything $client [lindex $arg 2] "\[[log:time $client]\]:\00310 [lindex $arg 0] changed topic to \"[lindex $arg 3]\017\00310\""
}

proc log:nick {client arg} {
	if {![string equal -nocase [lindex $arg 1] "NICK"]} {return exclude}
	setctx $client
	foreach chan [internalchannels] {
		if {[lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower $chan]] == -1} {
			if {[onchan [lindex $arg 2] $chan]} {
				log:everything $client $chan "\[[log:time $client]\]:\00310 [lindex [split [lindex $arg 0] !] 0] changed nicks to [lindex $arg 2]"
			}
		}
	}
}

proc log:mode {client arg} {
	if {![string equal -nocase [lindex $arg 1] "MODE"] || !([lsearch [split [getbncuser $client tag offlinelog.exclude] ,] [string tolower [lindex $arg 2]]] == -1)} {return exclude}
	log:everything $client [lindex $arg 2] "\[[log:time $client]\]:\00313 [lindex [split [lindex $arg 0] !] 0] changed mode [lindex $arg 3] [lrange $arg 4 end]"
}

proc log:time {client} {
	return [clock format [expr {[clock seconds] + [getbncuser $client timezone] * 60}] -format {%H:%M:%S} -gmt 1]
}

proc log:everything {client chan arg} {
	set r [open users/$client.clog a+]; puts $r ":-sBNC!core@shroudbnc.info PRIVMSG $chan :$arg"; close $r
}

proc log:playlog {client} {
	setctx $client
	if {![file exists users/$client.clog]} {return empty}
	set fd [open users/$client.clog r]
	set logfile { }
	while {![eof $fd]} {
		set tmp [gets $fd]
		if {[eof $fd]} {break}
		set logfile [lappend logfile [string trim $tmp]]
	}
	close $fd
	foreach tmp $logfile {
		putclient "$tmp"
	}
	file delete "users/$client.clog"
	return done
}