Index: Threat-1.0.lua
===================================================================
--- Threat-1.0.lua	(revision 40751)
+++ Threat-1.0.lua	(working copy)
@@ -866,6 +866,7 @@
 	for k in pairs(globalThreatAdjustments) do
 		globalThreatAdjustments[k] = nil
 	end
+	self:PublishThreatToKLHTM(nil)
 	self:TriggerEvent("Threat_ThreatUpdated", player, partyUnits[player], self.GlobalTarget, 0)
 end
 
@@ -908,6 +909,7 @@
 		self:SendCommMessage("GROUP", "THREAT_UPDATE", playerHash, petHash)
 		
 		if playerHash then
+			self:PublishThreatToKLHTM(playerHash)
 			playerHash = del(playerHash)
 		end
 		if petHash then
@@ -1208,6 +1210,8 @@
 	
 	if self:DoesPlayerHavePet() and self:GetPetModule().petName == targetPlayer then
 		self:GetPetModule():_addTargetThreat(threat, targetEnemy)
+	elseif partyMemberUsesKLHTM[targetPlayer] then
+		self:MisdirectToKLHTM(targetPlayer, threat)
 	else
 		self:SendCommMessage("GROUP", "MISDIRECT_THREAT", targetPlayer, targetEnemy, threat)
 	end
@@ -1313,7 +1317,10 @@
 
 function ThreatLib:CHAT_MSG_ADDON(prefix, message, distribution, sender)
 	if prefix == "KLHTM" and (distribution == "PARTY" or distribution == "RAID") then
-		partyMemberUsesKLHTM[sender] = true
+		if sender ~= playerName and not partyMemberUsesKLHTM[sender] then
+			partyMemberUsesKLHTM[sender] = true
+			self:Debug("New KLHTM user: %s", sender)
+		end
 		local command, data = message:match("^(%a+) ?(.*)$")
 		if command then
 			local func = self.OnKLHTMMessage[command]
@@ -1324,75 +1331,185 @@
 	end
 end
 
-function ThreatLib:GetKLHTMUsers()
-	return partyMemberUsesKLHTM
-end
-
-function ThreatLib:IsThreatLibPeer(name)
-	return name == playerName or partyMemberRevisions[name] and partyMemberRevisions[name] >= LAST_BACKWARDS_COMPATIBLE_REVISION or false
-end
-
 ThreatLib.OnKLHTMMessage = {}
 
 function ThreatLib.OnKLHTMMessage:t(sender, data)
-
-	-- ignore partymembers that are silly enough to run KLHTM and Threat-1.0
-	-- This semi-legally uses the partymemberLocales table to achieve its goal.
-	if sender == playerName or partyMemberRevisions[sender] then
+	local _ = partyUnits[nil] -- refresh if need be
+	if not partyMemberUsesKLHTM[sender] then
 		return
 	end
 	
 	local threat = tonumber(data)
-	if not threat then
-		return
+	if threat then
+		self:ThreatUpdatedForUnit( sender, self.KLHTMtarget or "_GLOBAL_", threat)
 	end
-	-- FIXME: Use mob name auto-localization here
-	if self.KLHTMtarget then
-		self:ThreatUpdatedForUnit( sender, self.KLHTMtarget, threat)
-	else
-		self:ThreatUpdatedForUnit( sender, "_GLOBAL_", threat )
-	end
 end
 
 function ThreatLib.OnKLHTMMessage:target(sender, data)
-	self:Debug("KTM Target set to %s", data)
 	if data and type(data) == "string" then
-		self.KLHTMtarget = data
+		local senderUnit = partyUnits[sender]
+		if IsGroupOfficer(senderUnit) then
+			local senderTargetUnit = senderUnit..'target'
+			if UnitExists(senderTargetUnit) then
+				self.KLHTMtarget = UnitName(senderTargetUnit)
+			else
+				self.KLHTMtarget = self:TranslateForeignMobName(data)
+			end
+			self:Debug("KTM Target set to %s (%s) by %s", self.KLHTMtarget, data, sender)
+		end
 	end
 end
 
 function ThreatLib.OnKLHTMMessage:cleartarget(sender, data)
-	self:Debug("KTM Target cleared")
-	self.KLHTMtarget = nil
+	local senderUnit = partyUnits[sender]
+	if IsGroupOfficer(senderUnit) then
+		self.KLHTMtarget = nil
+		self:Debug("KTM Target cleared by %s", sender)
+	end
 end
 
-function ThreatLib:SendKLHTMMessage(command, data)
-	local _ = partyUnits[nil] -- refresh if need be
-	if not next(partyMemberUsesKLHTM) then -- no point
-		return
+function ThreatLib.OnKLHTMMessage:misdirection(sender, data)
+	local targetPlayer, amount = data:match("^(%S+) (%d+)$")
+	if targetPlayer == playerName and select(2, UnitClass(partyUnits[sender])) == "HUNTER" then
+		local targetEnemy = self.KLHTMtarget or "_GLOBAL_"
+		amount = tonumber(amount)
+		self:Debug("Misdirected threat from KLHTM: %q (%q)", amount, enemy)
+		self:GetModule("ClassCore").activeModule:_addTargetThreat(amount, targetEnemy)
 	end
-	if _G.klhtm then -- let KLHTM proper handle it.
+end
+
+---------------------------------------------------------------------------
+-- KTM message outputing
+---------------------------------------------------------------------------
+
+-- Empty KLHTM output methods
+
+do
+	local function noop() end
+	
+	ThreatLib.PublishThreatToKLHTM = noop
+	ThreatLib.MisdirectToKLHTM = noop
+	ThreatLib.IsKLHTMSupportLoaded = noop
+	ThreatLib.IsKLHTMBroadcastEnabled = noop
+	ThreatLib.IsKLHTMBroadcastActive = noop
+	ThreatLib.SendKLHTMMessage = noop
+end
+
+-- Real KLHTM output methods
+
+local function LoadKLHTMBroadcastSupport()
+
+	-- Won't load if the real KLHTM has been loaded
+	if _G.klhtm then
+		ThreatLib:Debug("Will not load KLHTMBroadcastSupport because KLHTM is loaded")
 		return
 	end
-	local distribution
-	if GetNumRaidMembers() > 0 then
-		distribution = "RAID"
-	elseif GetNumPartyMembers() > 0 then
-		distribution = "PARTY"
-	else
-		return
+	
+	-- Locals
+	local fakeKLHTMVersion = "19.18"
+	local lastPublishedThreat
+	local enabled = true
+
+	-- Real methods
+	
+	function ThreatLib:EnableKLHTMBroadcast(value)
+		if enabled and not value then
+			enabled = nil
+			self:Debug("KLHTM broadcast disabled")
+		elseif not enabled and value then
+			enabled = true
+			self:Debug("KLHTM broadcast enabled")
+		end
 	end
+		
+	function ThreatLib:IsKLHTMBroadcastActive()
+		return enabled and next(partyMemberUsesKLHTM) and self:IsActive()
+	end
 	
-	local message
-	if data then
-		message = command .. " " .. data
-	else
-		message = command
+	function ThreatLib:PublishThreatToKLHTM(playerHash)
+		if not enabled then return end
+		local threat 
+		if playerHash and next(playerHash) then
+			if self.KLHTMtarget then
+				threat = playerHash[TailoredBinaryCheckSum[self.KLHTMtarget]]
+			else
+				threat = 0
+				for k,v in pairs(playerHash) do
+					threat = threat + v
+				end
+			end
+		else
+			threat = 0
+		end
+		if threat and threat ~= (lastPublishedThreat or 0) then
+			if self:SendKLHTMMessage('t', threat) then
+				self:Debug('Sent KLHTM threat: %q', threat)
+				lastPublishedThreat = threat
+			end
+		end
 	end
 	
-	ChatThrottleLib:SendAddonMessage("NORMAL", "KLHTM", message, distribution)
+	function ThreatLib:MisdirectToKLHTM(targetPlayer, threat)
+		if self:SendKLHTMMessage('misdirection', ("%s %d"):format(targetPlayer, threat)) then
+			self:Debug('Redirected KLHTM threat on %q: %q', targetPlayer, threat)
+		end
+	end
+	
+	function ThreatLib:SendKLHTMMessage(command, data)
+		local _ = partyUnits[nil] -- refresh if need be
+		if not enabled or not next(partyMemberUsesKLHTM) then -- no point
+			return
+		end
+		local distribution
+		if GetNumRaidMembers() > 0 then
+			distribution = "RAID"
+		elseif GetNumPartyMembers() > 0 then
+			distribution = "PARTY"
+		else
+			return
+		end
+		
+		local message
+		if data then
+			message = command .. " " .. data
+		else
+			message = command
+		end
+		
+		ChatThrottleLib:SendAddonMessage("NORMAL", "KLHTM", message, distribution)
+		return true
+	end
+	
+	function ThreatLib.OnKLHTMMessage:versionquery(sender, data)
+		local senderUnit = partyUnits[sender]
+		if enabled and IsGroupOfficer(senderUnit) then
+			if self:SendKLHTMMessage("versionresponse", fakeKLHTMVersion) then
+				self:Debug("Replied %s to %s's versionquery", fakeKLHTMVersion, sender)
+			end
+		end
+	end
+	
+	function ThreatLib:IsKLHTMBroadcastEnabled()
+		return enabled
+	end
+	
+	function ThreatLib:IsKLHTMSupportLoaded()
+		return true
+	end
+
 end
 
+function ThreatLib:EnableKLHTMBroadcast(value)
+	if value then
+		local res, reason = pcall(LoadKLHTMBroadcastSupport)
+		if res then
+			self:Debug("KLHTM broadcast support loaded")
+		else
+			self:Debug("Could not load KLHTM broadcast support: %q", reason)
+		end
+	end
+end
+
 ------------------------------------------------------------------------------------
 -- Mob name translations, for groups with clients of multiple locales
 -- This automatically translates mob names across locales
