# *** READ THIS ***

# INSTALLATION

# i) Place this TCL into your eggdrop/scripts directory,
# ii) make the usual 'source scripts/expose.tcl'
#     entry at the end of eggdrop.conf,
# iii) and rehash the bot as normal.

# CONFIGURATION

# The configuration section is below. Those who insist on
# tinkering will find another section beneath that defining
# various constants used by the script, including nearly all
# the outputted text, and the regexps used to strip the
# quotes from the HTML.
# Don't muck with this if you don't know what you're doing.

# COMMANDS

# The following commands are recognised by default:

# !exposed
#     - this displays a random quote from the exposed.coldfront.org quote
#       database. The quote will always appear in a public
#       channel, because the script will ignore entries in
#       its random quote cache that have a length exceeding
#       exposed_max_public_line_length.
#	  If you didn't understand this, don't worry about it.

# !exposed <text>
#     - Needless to say, the < and > symbols should not be
#       typed in as part of the command.
#       (Unless you're searching for a nick, of course.)
#       Fetches the quote numbers of the first N quotes
#       (N being defined by exposed_max_search_results in the
#       config section below) that match text <text>.

# !exposed <number>
#     - Again, no < and > symbols, please.
#       Fetches a specific numbered quote from the QDB.
#       If it contains less lines than the
#       exposed_max_public_line_length setting,
#       the quote will be displayed publically. If not, it
#       will be privately /msged or /noticed to the use
#       who requested it.

# HOW IT WORKS

# If you want to get on and configure the damn thing, skip this
# section.

# The random quote function was the first written. It makes
# an HTTP query to the 'Random' link on the exposed.coldfront.org front page.
# It receives the response and then uses various regexp filters
# to extract the quotes and place them in a TCL list (exposed_cache).
# Meanwhile the numbers of the quotes are stored in another list
# (exposed_number_list). The position of the next item that is
# to be displayed from these lists is marked by the
# exposed_cache_pointer_position variable. Requesting quotes is
# disabled when the cache is empty and, if not already running,
# an HTTP query is attempted to refill the cache. The cache will
# also be refilled when the pointer hits the end of the list.
# When a quote is requested, exposed_cache[exposed_cache_pointer_position]
# and exposed_number_list[exposed_cache_pointer_position] are read,
# the pointer is incremented, and the resulting texts are again
# regexp filtered by the exposed_output function for de-escaping of
# HTML entities (&nbsp; etc). If the length of the quote exceeds
# exposed_max_public_line_length, the pointer is repeatedly
# incremented until this condition is not true. If
# exposed_max_public_line_length is set low, only a few quotes will
# be displayed by this command per HTML query.
# The TCL commands to display the quote in the channel are placed
# on the event queue with the 'after' command and told to execute
# a certain time apart (this time being set by the
# exposed_seconds_per_line setting). 

# The !exposed <number> command works similarly to the random quote
# function and borrows a lot of code from it. This time, an HTTP 
# query is made to the appropriate exposed.coldfront.net web page for a certain
# numbered quote. The returned HTML is stripped of its tags as
# before. If the quote is longer than exposed_max_public_line_length,
# it is privately messaged to the requesting nick. Otherwise,
# it is displayed in the channel.

# The !exposed <text> command is a little different to the other two.
# It makes a request using the search function of the exposed.coldfront.net
# website (for a maximum number of quotes set by
# exposed_max_search_results), and parses out only the quote numbers
# of the returned HTML. These are always displayed publically.

# ---------------------------------------------
# *** CONFIGURATION SECTION ***
#
set exposed_command "!exposed"
#
# ^-- the public command to invoke the script
#
#     the suffices '_usage' and '_version', when appended onto the
#     end of this command, also form commands.
#     i.e. if exposed_command were, say, "!moose", then the commands
#     "!exposed_usage" and "!exposed_version"
#     would now become "!moose_usage" and "!moose_version".
#
#
set exposed_max_public_line_length 8
#
# ^-- this defines the longest quote (number of lines) which the
#     script will display publically rather than as a private message.
#     Somewhere between 4 and 12 should be good depending on how
#     busy your channel is.
#
#
set exposed_seconds_per_quote 15
#
# ^-- this defines the number of seconds that the bot will wait
#     for after displaying one quote before it allows another
#     to be requested. Set to 0 to disable this floodprotection.
#
#
set exposed_seconds_per_line 0
#
# ^-- this defines the number of seconds that the bot will wait
#     between displaying two lines of the same quote.
#     Bear in mind that eggdrops won't display more than one
#     line per few seconds even if this is set to 0.
#
#
set exposed_max_search_results 10
#
# ^-- maximum number of search results returned by a
#     !exposed <text> query.
#     Bear in mind that the maximum IRC server line length will
#     limit you if you set this to something large (> 25 or so).
#
#
set exposed_enable_debug 1
#
# ^-- this should always be set to 0 unless you're having some
#     issues, i.e. the script isn't working. Beware that it will
#     spray all sorts of debugging crap into the eggdrop logs.
#
#
set exposed_use_blocking_number_fetch 1
set exposed_use_blocking_search_fetch 1
set exposed_use_blocking_random_fetch 0
#
# ^-- these three define the mode used to make the queries to the
#     exposed.coldfront.org webserver. If you don't understand the difference
#     between blocking and non-blocking (callback) fetch, you're
#     probably better leaving them as they are.
#     This is the default because it has been discovered through
#     experimentation than blocking fetches are a lot faster than non-
#     blocking ones, at least on my eggdrop (1.6.12 / linux 2.4.20).
#     However some may consider non-blocking fetches to be more stable.
#     Feel free to set them to 0 but don't be surprised if it's as
#     slow as a snail.
#
#
set exposed_lock_reset_time_ms 600000
#
# ^-- this is the amount of time in milliseconds the script
#     will wait for before removing a stale exposed_lock lock.
#     This attempts to combat failed fetch-related siezeups,
#     and their associated annoying public messages.
#     Currently 10 minutes. You shouldn't need to change it.
#     This is new and experimental. I don't know whether it
#     solves the problem successfully or not.
#
#
set exposed_use_notices 1
#
# ^-- this specifies whether lengthy quotes should be /noticed to
#     the recipient's nick or /msged there. Set to 0 to use /msg.
#     Set to 1 to use /notice.
#
#
set exposed_spit_channel_list [list]

# lappend exposed_spit_channel_list "#somechannel 5"
# lappend exposed_spit_channel_list "#someotherchannel 10"
# lappend exposed_spit_channel_list "#anotherchannel 60"
# lappend exposed_spit_channel_list "#\[channel_with_brackets\] 120"
# # ... more lappend lines here ...

#
# ^-- if you want the bot to spit out random quotes into a channel
#     or channels, you will need to add the names of the channels
#     to which this applies by uncommenting one or more 'lappend ...' lines
#     here and changing the channel name and the number that follows
#     it. This number is the number of minutes you want the bot to
#     wait between spitting out one quote and spitting out the next.
#     It may be set independently for each of the channels on the list.
#     There must be a space between the channel name and the number.
#	If your channel name contains [square brackets], you will need
#	to slash-escape the brackets ( '[' -> '\[' , ']' -> '\]' )
#	as in the example above.

# ----------------------------------------------
# *** DEFAULT CHANNEL (PUBLIC) COMMANDS ***

# !exposed          :  displays a random quote from the exposed.coldfront.org QDB;
# !exposed <number> :  displays a specific quote from the exposed.coldfront.org QDB;
# !exposed <text>   :  searches for quotes matching <text> in the exposed.coldfront.net
#                   QDB and displays their numbers;
# !exposed_version  :  shows the script version;
# !exposed_usage    :  shows the commands that this script supports.

## ---------------------------------------------
## Don't change anything below this line.
## ---------------------------------------------
#http://exposed.coldfront.net/?searched&sortby=rating&search=Mag
#	set url $query_prefix$query_suffix_search[http::formatQuery $query_get_parm_number $query_get_parm_search $text]
package require http

set agent "Mozilla"
set query_prefix "http://exposed.coldfront.net/?"
set query_suffix_random "random"
set query_suffix_number ""
set query_suffix_search "searched"
set query_get_parm_number "sortby=rating"
set query_get_parm_search "search="
set exposed_cache_pointer_position 0
set exposed_cache [list]
set exposed_number_list [list]
set exposed_lock 0
set exposed_result_regexp "<span class='quote'>(.*?)</a>(.*</html>)"
set exposed_number_regexp "#(\[0-9\])</a>"
set exposed_newline_regexp "<br />|</span></div>"

# text strings

set exposed_ver 					"!exposed for exposed.coldfront.net 1.0 (working on searh and number display) by Merlin"
set exposed_search_result_individual_prefix 	""
set exposed_search_result_separator 		" | "
set exposed_command_suffix_debug 		"_debug"
set exposed_command_suffix_version 		"_version"
set exposed_command_suffix_usage 		"_usage"
set exposed_command_suffix_restart 		"_restart"

set exposed_errortext_http_fetch 		"error: \002$exposed_command\002: command is locked while HTTP fetch is performed. Try again in 10 seconds."
set exposed_errortext_failed_init 		"error: \002$exposed_command\002: exposed_cache is empty (failed initialisation)"
set exposed_errortext_cache_spent		"error: \002$exposed_command\002: exposed_cache is spent (HTTP lookup to refresh it must have failed ... retrying)" 
set exposed_errortext_fetch_locked		"error: \002$exposed_command\002: exposed_lock is 1, cannot continue."
set exposed_errortext_infinite_loop		"error: \002$exposed_command\002: safety_measure > 100 in exposedCallback, assuming infinite loop and terminating"
set exposed_errortext_spitlist_invalid		"error: \002$exposed_command\002: exposed_spit_channel_list contains illegal entries : check configuration"
set exposed_unlock_warning				"$exposed_ver: WARNING: waited longer than $exposed_lock_reset_time_ms for query, unlocking."

set exposed_text_search_result_prefix 		"\002$exposed_command\002 search results: "
set exposed_text_usage_1 				"\002$exposed_command\002: usage: $exposed_command for a random quote"
set exposed_text_usage_2 				"              $exposed_command <number> for a specific quote"
set exposed_text_usage_3 				"              $exposed_command <text> to search for a quote containing text <text> (does not work yet)"
set exposed_text_no_search_results 		"\002$exposed_command\002: no results found for search"
set exposed_text_version 				"\002$exposed_ver"
set exposed_text_too_many_lines_1		"\002$exposed_command\002: quote has too many lines to display in public channel (max $exposed_max_public_line_length, quote has "
set exposed_text_too_many_lines_2		"): sending as privmsg instead"
set exposed_text_quote_not_found			"\002$exposed_command\002: quote not found"
set exposed_text_running				"$exposed_ver: RUNNING, use $exposed_command to invoke."

bind pubm * "* $exposed_command*" exposed_decide
bind pubm * "* $exposed_command$exposed_command_suffix_usage" exposed_usage_wrapper
bind pubm * "* $exposed_command$exposed_command_suffix_version" exposed_version

#bind pubm * "* $exposed_command$exposed_command_suffix_restart" exposed_restart
#bind pubm * "* $exposed_command$exposed_command_suffix_debug" exposed_debug

## -------------------------------------------------
## DEFINITELY don't change anything below THIS line.
## -------------------------------------------------

set startup_time [clock clicks -milliseconds]
set exposed_last_quote_time [expr $startup_time - 60000]
set exposed_nick_token_hash(0) 0
set exposed_channel_token_hash(0) 0

## we need to disable any 'after' commands that may still be on
## the event queue from a previous invocation:

set exposed_after_list [after info]

foreach token $exposed_after_list {
	set id_info [after info $token]
	if { [regexp .*exposed_spit.* $id_info] } {
		if { $exposed_enable_debug } {
			putlog "!exposed: procname matched exposed_spit: removing from queue"
		}
		after cancel $token
	}
}

proc exposed_debug { n u h c t } {

	global exposed_cache
	global exposed_lock
	global exposed_cache_pointer_position
	global exposed_number_list

	op "list length: [llength $exposed_cache] | number list length: [llength $exposed_number_list] | lock: $exposed_lock | exposed_cache_pointer_position: $exposed_cache_pointer_position" $c

}

proc locked_error { c } {
	global exposed_errortext_http_fetch
	op $exposed_errortext_http_fetch $c
}

proc exposed_decide { n u h c t } {

	global exposed_command
	global exposed_command_suffix_debug
	global exposed_command_suffix_restart
	global exposed_command_suffix_usage
	global exposed_command_suffix_version
	global exposed_last_quote_time
	global exposed_seconds_per_quote
	global exposed_enable_debug

	if { $exposed_enable_debug } {
		putlog "exposed_decide $n $u $h $c $t"
	}

	if { [expr "$exposed_last_quote_time + ($exposed_seconds_per_quote * 1000)"] > [clock clicks -milliseconds] } {
		if { $exposed_enable_debug } {
			putlog "exposed_decide: returned due to inter-quote time being exceeded: b_l_q_t = $exposed_last_quote_time | b_s_p_q = $exposed_seconds_per_quote | clock clicks = [clock clicks -milliseconds]"
		}
		return
	}

	if { [regexp "($exposed_command$exposed_command_suffix_debug *)|($exposed_command$exposed_command_suffix_restart *)|($exposed_command$exposed_command_suffix_usage *)|($exposed_command$exposed_command_suffix_version)" $t] } {
		if { $exposed_enable_debug } {
			putlog "exposed_decide: returned due to detection of valid alternate command suffix"
		}
		return
	}

	if { [string length $t] > [string length $exposed_command] } {
		set blah "^$exposed_command *\[0-9\]+$"
		if { [regexp $blah $t match] } {
			exposed_number $n $u $h $c $t
			return
		}
		exposed_search $n $u $h $c $t
	} else {
		exposed_random $n $u $h $c $t
	}

}

proc exposed_search { n u h c t } {

	global exposed_command
	global agent
	global query_get_parm_search
	global query_get_parm_number
	global query_prefix
	global query_suffix_search
	global exposed_max_search_results
	global exposed_enable_debug
	global exposed_nick_token_hash
	global exposed_channel_token_hash
	global exposed_use_blocking_search_fetch

	if { $exposed_enable_debug } {
		putlog "exposed_search $n $u $h $c $t"
	}
		
	regexp "^$exposed_command *(.*)$" $t blah text

	http::config -useragent $agent
#	set url $query_prefix$query_suffix_search[http::formatQuery $query_get_parm_search $text $query_get_parm_number $exposed_max_search_results]
	set url $query_prefix$query_suffix_search[http::formatQuery $query_get_parm_number $query_get_parm_search $text]
	if { $exposed_use_blocking_search_fetch == 0 } {
		set token [http::geturl $url -command exposedCallback_search]
		set exposed_nick_token_hash($token) $n
		set exposed_channel_token_hash($token) $c
	} else {
		set token [http::geturl $url]
		set exposed_nick_token_hash($token) $n
		set exposed_channel_token_hash($token) $c
		exposedCallback_search $token
	}

}

proc exposedCallback_search { token } {

	global exposed_result_regexp
	global exposed_number_regexp
	global exposed_max_search_results
	global exposed_search_result_separator
	global exposed_text_search_result_prefix
	global exposed_command
	global exposed_search_result_individual_prefix
	global exposed_text_no_search_results
	global exposed_enable_debug
	global exposed_nick_token_hash
	global exposed_channel_token_hash

	set nick $exposed_nick_token_hash($token)
	set channel $exposed_channel_token_hash($token)
	unset exposed_nick_token_hash($token)
	unset exposed_channel_token_hash($token)

	if { $exposed_enable_debug } {
		putlog "exposedCallback_search $token $nick $channel"
	}

	catch {

		set result [http::data $token]
		unset $token
		set search_results [list]

		set count 0

		while { [regexp $exposed_number_regexp $result blah numero the_rest] } {

			if { $count > $exposed_max_search_results } {
				break
			}

			lappend search_results $numero

			set result $the_rest
			incr count

		}

		set search_result_string $exposed_text_search_result_prefix
		set separator ""

		foreach search_result $search_results {
			set search_result_string $search_result_string$separator$exposed_search_result_individual_prefix$search_result
			set separator $exposed_search_result_separator
		}

		if { $count == 0 } {
			op $exposed_text_no_search_results $channel
			return
		}

		op $search_result_string $channel

		return

	} errorstg

	putlog $errorstg

}

proc exposed_number { n u h c t } {
	global exposed_enable_debug
	if { $exposed_enable_debug } {
		putlog "exposed_number $n $u $h $c $t"
	}
	regexp "\[0-9\]+" $t match
	exposed_dot_org_fetch_number $match $n $c
}

proc exposed_usage_wrapper { n u h c t } {
	exposed_usage $c
}

proc exposed_usage { c } {

	global exposed_text_usage_1
	global exposed_text_usage_2
	global exposed_text_usage_3

	op $exposed_text_usage_1 $c
	op $exposed_text_usage_2 $c
	op $exposed_text_usage_3 $c

}

proc exposed_version { n u h c t } {
	global exposed_text_version
	op $exposed_text_version $c
}

proc exposed_random { n u h c t } {

	global exposed_cache
	global exposed_cache_pointer_position
	global exposed_lock
	global exposed_number_list
	global exposed_command
	global exposed_errortext_failed_init
	global exposed_errortext_cache_spent
	global exposed_enable_debug
	global exposed_lock_reset_time_ms

	if { $exposed_enable_debug } {
		putlog "exposed_random $n $u $h $c $t"
	}

#	if { $exposed_lock != 0 } {
#		locked_error $c
#		return
#	}
	if { $exposed_lock != 0 } {
		locked_error $c
		if { [expr [clock clicks -milliseconds] - $exposed_lock] < $exposed_lock_reset_time_ms } {
#			putlog $exposed_ver $exposed_errortext_fetch_locked
			return
		}
		putlog $exposed_unlock_warning
		set exposed_lock 0
	}

	if { [llength $exposed_cache] == 0 } {
		op "exposed_cache is empty - refilling ..." $c
		exposed_dot_org_fetch_random
		return
	}

	if { $exposed_cache_pointer_position >= [llength $exposed_cache] } {
		op "exposed_cache is empty - refilling ..." $c
		exposed_dot_org_fetch_random
		return
	}

	if { [exposed_output [lindex $exposed_cache $exposed_cache_pointer_position] [lindex $exposed_number_list $exposed_cache_pointer_position] $c $n 1] == 0 } {
		set failed 1
	} else {
		set failed 0
	}

	incr exposed_cache_pointer_position

	if { $exposed_cache_pointer_position >= [llength $exposed_cache] } {
		if { $failed == 1 } {
			locked_error $c
		}
		exposed_dot_org_fetch_random
	} else {
		if { $failed == 1 } {
			exposed_random $n $u $h $c $t
		}
	}
}

proc exposed_output { text number c n allow_failure } {

	global exposed_max_public_line_length
	global exposed_command
	global exposed_text_too_many_lines_1
	global exposed_text_too_many_lines_2
	global exposed_seconds_per_line
	global exposed_last_quote_time
	global exposed_enable_debug
	global exposed_use_notices
	global exposed_newline_regexp

	if { $exposed_enable_debug } {
		putlog "exposed_output $text $number $c $n $allow_failure"
	}

	regsub -all "(\r)|(\n)" "$text " "" tmp4
	regsub -all $exposed_newline_regexp $tmp4 "\n" tmp5
	regsub -all "&gt;" $tmp5 ">" tmp6
	regsub -all "&lt;" $tmp6 "<" tmp7
	regsub -all "&quot;" $tmp7 "'" tmp8
	regsub -all "&nbsp;" $tmp8 " " tmp9
	regsub -all "amp;" $tmp9 "" tmp10

	set lst [split $tmp10 "\n"]

	if { [llength $lst] > $exposed_max_public_line_length } {
		if { $allow_failure } {
			return 0
		}
		op $exposed_text_too_many_lines_1[llength $lst]$exposed_text_too_many_lines_2 $c
		if { $exposed_use_notices } {
			set target "NOTICE $n"
		} else {
			set target "PRIVMSG $n"
		}
	} else {
		set target "PRIVMSG $c"
	}

	set delay_increment [expr $exposed_seconds_per_line * 1000]
	set delay 0

	set exposed_last_quote_time [clock clicks -milliseconds]

	# fix for brackets-in-channel-name bug (thanks CGlass)
	regsub -all \\\] $target \\\] target
	regsub -all \\\[ $target \\\[ target

	foreach tmp11 $lst {
		# these two might look like NOPs. They aren't. Remember square brackets are reserved in regexp too.
		regsub -all \\\] $tmp11 \\\] tmp11
		regsub -all \\\[ $tmp11 \\\[ tmp11
		if { $number == -1 } {
			set to_ex "putserv \"$target :\002|exposed|\002 $tmp11\""
			after $delay $to_ex
		} else {
			set to_ex "putserv \"$target :\002|exposed $number|\002 $tmp11\""
			after $delay $to_ex
		}
		set delay [expr $delay + $delay_increment]
	}

	return 1

}

proc exposed_restart { n u h c t } {
	exposed_init
}

proc exposed_init { } {

	global exposed_ver
	global exposed_spit_channel_list
	global exposed_error
	global exposed_errortext_spitlist_invalid
	global exposed_enable_debug
	global exposed_lock

	set exposed_lock 0

	exposed_dot_org_fetch_random

	if { [llength $exposed_spit_channel_list] > 0 } {

		if { [check_exposed_spit_channel_list] == 0 } {

			putlog $exposed_errortext_spitlist_invalid
			die

		} else {

			set i 0

			while { $i < [llength $exposed_spit_channel_list] } {

				regexp "^(.+) (\[0-9\]+)$" [lindex $exposed_spit_channel_list $i] blah channel delay
				set delay_ms [expr $delay * 60000]

				# fix for brackets-in-channel-name bug (thanks CGlass)
				regsub -all \\\] $channel \\\] channel
				regsub -all \\\[ $channel \\\[ channel
				set to_ex "exposed_spit $channel $delay_ms"

				if { $exposed_enable_debug } {
					putlog "!exposed: placing spit command on event queue : after $delay_ms $to_ex"
				}

				after $delay_ms $to_ex

				incr i

			}
		}
	}
}

proc exposed_spit { channel delay } {

	global exposed_enable_debug

	if { $exposed_enable_debug } {
		putlog "exposed_spit $channel $delay"
	}

	exposed_random \000 \000 \000 $channel \000

	regsub -all \\\] $channel \\\] channel
	regsub -all \\\[ $channel \\\[ channel

	set to_ex "exposed_spit $channel $delay"
	if { $exposed_enable_debug } {
		putlog "!exposed: placing spit command on event queue : after $delay $to_ex"
	}
	after $delay $to_ex

}

proc check_exposed_spit_channel_list { } {

	global exposed_spit_channel_list

	set i 0

	while { $i < [llength $exposed_spit_channel_list] } {
		if { [regexp "^.+ \[0-9\]+$" [lindex $exposed_spit_channel_list $i]] == 0 } {
			return 0
		} else {
			incr i
		}
	}

	return 1

}

proc exposed_dot_org_fetch_number { n nick c } {

	global agent
	global query_prefix
	global query_suffix_number
	global exposed_enable_debug
	global exposed_nick_token_hash
	global exposed_channel_token_hash
	global exposed_use_blocking_number_fetch

	if { $exposed_enable_debug } {
		putlog "exposed_dot_org_fetch_number $n $nick $c"
	}

	set query $query_prefix$query_suffix_number$n

	http::config -useragent $agent

	if { $exposed_use_blocking_number_fetch == 0 } {
		set token [http::geturl $query -command exposedCallback_number]
		set exposed_nick_token_hash($token) $nick
		set exposed_channel_token_hash($token) $c
	} else {
		set token [http::geturl $query]
		set exposed_nick_token_hash($token) $nick
		set exposed_channel_token_hash($token) $c
		exposedCallback_number $token
	}

}

proc exposed_dot_org_fetch_random { } {

	global agent
	global query_prefix
	global query_suffix_random
	global exposed_lock
	global exposed_command
	global exposed_errortext_fetch_locked
	global exposed_ver
	global exposed_enable_debug
	global exposed_use_blocking_random_fetch

	if { $exposed_enable_debug } {
		putlog "exposed_dot_org_fetch_random"
	}

	set exposed_lock [clock clicks -milliseconds]

	http::config -useragent $agent

	if { $exposed_use_blocking_random_fetch == 0 } {
		set token [http::geturl $query_prefix$query_suffix_random -command exposedCallback_random]
	} else {
		set token [http::geturl $query_prefix$query_suffix_random]
		exposedCallback_random $token
	}

}

proc exposedCallback_number { token } {

	global exposed_result_regexp
	global exposed_command
	global exposed_text_quote_not_found
	global exposed_enable_debug
	global exposed_nick_token_hash
	global exposed_channel_token_hash

	if { $exposed_enable_debug } {
		putlog "exposedCallback_number $token"
	}

	set nick $exposed_nick_token_hash($token)
	set c $exposed_channel_token_hash($token)
	unset exposed_nick_token_hash($token)
	unset exposed_channel_token_hash($token)

	if { $exposed_enable_debug } {
		putlog "exposedCallback_number $token $nick $c"
	}

	catch {

		set result [http::data $token]
		unset $token

		if { [regexp $exposed_result_regexp $result tmp data] == 1} {
			exposed_output $data -1 $c $nick 0
		} else {
			op $exposed_text_quote_not_found $c
		}

		return 1

	} blah

	if { $exposed_enable_debug } {
		putlog $blah
	}

	return 0

}

proc exposedCallback_random { token } {

	global exposed_lock
	global exposed_cache
	global exposed_cache_pointer_position
	global exposed_result_regexp
	global exposed_number_regexp
	global exposed_number_list
	global exposed_command
	global exposed_errortext_infinite_loop
	global exposed_ver
	global exposed_enable_debug
	global exposed_max_public_line_length
	global exposed_newline_regexp

	set exposed_cache [list]
	set exposed_number_list [list]

	if { $exposed_enable_debug } {
		putlog "exposedCallback_random $token"
	}

	catch {

		set result [http::data $token]
		unset $token

		set safety_measure 0
		set limit [expr $exposed_max_public_line_length + 1]

		while { [regexp $exposed_result_regexp $result tmp data the_rest] } {

			if { [regexp "(.*$exposed_newline_regexp.*){$limit}" $data] == 0 } {
				if { [regexp $exposed_number_regexp $result blah numero] == 1 } {
					lappend exposed_number_list $numero
				} else {
					lappend exposed_number_list -1
				}
				lappend exposed_cache $data
			}

			set result $the_rest
			incr safety_measure

			if { $safety_measure > 100 } {
				putlog $exposed_ver $exposed_errortext_infinite_loop
				set exposed_lock 0
				return
			}
		}

		set exposed_cache_pointer_position 0
		set exposed_lock 0
		return

	} errorstg

	if { $exposed_enable_debug } {
		putlog $errorstg
	}

	set exposed_lock 0

}

proc op { o c } {
	putserv "PRIVMSG $c :$o"
}

exposed_init

putlog $exposed_text_running
