local mod = Chatter:NewModule("URL Copy", "AceHook-3.0") local L = LibStub("AceLocale-3.0"):GetLocale("Chatter") mod.modName = L["URL Copy"] local gsub = _G.string.gsub local ipairs = _G.ipairs local pairs = _G.pairs local fmt = _G.string.format local sub = _G.string.sub local tlds local style = "|cffffffff|Hurl:%s|h[%s]|h|r" local function Link(link, ...) if link == nil then return "" end return mod:RegisterMatch(fmt(style, link, link)) end local function Link_TLD(link, tld, ...) if link == nil or tld == nil then return "" end if tlds[tld:upper()] then return mod:RegisterMatch(fmt(style, link, link)) else return mod:RegisterMatch(link) end end local patterns = { -- X://Y url { pattern = "^(%a[%w%.+-]+://%S+)", matchfunc=Link}, { pattern = "%f[%S](%a[%w%.+-]+://%S+)", matchfunc=Link}, -- www.X.Y url { pattern = "^(www%.[-%w_%%]+%.%S+)", matchfunc=Link}, { pattern = "%f[%S](www%.[-%w_%%]+%.%S+)", matchfunc=Link}, -- "W X"@Y.Z email (this is seriously a valid email) --{ pattern = '^(%"[^%"]+%"@[-%w_%%%.]+%.(%a%a+))', matchfunc=Link_TLD}, --{ pattern = '%f[%S](%"[^%"]+%"@[-%w_%%%.]+%.(%a%a+))', matchfunc=Link_TLD}, -- X@Y.Z email { pattern = "(%S+@[-%w_%%%.]+%.(%a%a+))", matchfunc=Link_TLD}, -- XXX.YYY.ZZZ.WWW:VVVV/UUUUU IPv4 address with port and path { pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link}, { pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link}, -- XXX.YYY.ZZZ.WWW:VVVV IPv4 address with port (IP of ts server for example) { pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link}, { pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d:[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link}, -- XXX.YYY.ZZZ.WWW/VVVVV IPv4 address with path { pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%/%S+)", matchfunc=Link}, { pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%/%S+)", matchfunc=Link}, -- XXX.YYY.ZZZ.WWW IPv4 address { pattern = "^([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%)%f[%D]", matchfunc=Link}, { pattern = "%f[%S]([0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%.[0-2]?%d?%d%)%f[%D]", matchfunc=Link}, -- X.Y.Z:WWWW/VVVVV url with port and path { pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link_TLD}, { pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d/%S+)", matchfunc=Link_TLD}, -- X.Y.Z:WWWW url with port (ts server for example) { pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link_TLD}, { pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+):[0-6]?%d?%d?%d?%d)%f[%D]", matchfunc=Link_TLD}, -- X.Y.Z/WWWWW url with path { pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+)/%S+)", matchfunc=Link_TLD}, { pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+)/%S+)", matchfunc=Link_TLD}, -- X.Y.Z url { pattern = "^([-%w_%%%.]+[-%w_%%]%.(%a%a+))", matchfunc=Link_TLD}, { pattern = "%f[%S]([-%w_%%%.]+[-%w_%%]%.(%a%a+))", matchfunc=Link_TLD}, } local options = { mangleMumble = { type = "toggle", name = L["Parse Mumble links"], desc = L["Automatically inject your character's name into Mumble links, so you connect with your username prefilled."], get = function() return mod.db.profile.mangleMumble end, set = function(info, v) mod.db.profile.mangleMumble = v end }, mangleTeamspeak = { type = "toggle", name = L["Parse Teamspeak 3 links"], desc = L["Automatically inject your character's name into Teamspeak 3 links, so you connect with your username prefilled."], get = function() return mod.db.profile.mangleTeamspeak end, set = function(info, v) mod.db.profile.mangleTeamspeak = v end } } do local defaults = { profile = { mangleMumble = true, mangleTeamspeak = true } } local events = { "CHAT_MSG_BATTLEGROUND", "CHAT_MSG_BATTLEGROUND_LEADER", "CHAT_MSG_CHANNEL", "CHAT_MSG_EMOTE", "CHAT_MSG_GUILD", "CHAT_MSG_OFFICER", "CHAT_MSG_PARTY", "CHAT_MSG_RAID", "CHAT_MSG_RAID_LEADER", "CHAT_MSG_RAID_WARNING", "CHAT_MSG_PARTY_LEADER", "CHAT_MSG_SAY", "CHAT_MSG_WHISPER","CHAT_MSG_BN_WHISPER", "CHAT_MSG_WHISPER_INFORM", "CHAT_MSG_YELL", "CHAT_MSG_BN_WHISPER_INFORM","CHAT_MSG_BN_CONVERSATION" } function mod:OnInitialize() self.db = Chatter.db:RegisterNamespace("UrlCopy", defaults) end function mod:OnEnable() for _,event in ipairs(events) do ChatFrame_AddMessageEventFilter(event, self.filterFunc) end self:RawHook("SetItemRef", true) end function mod:OnDisable() for _,event in ipairs(events) do ChatFrame_RemoveMessageEventFilter(event, self.filterFunc) end end end do local tokennum, matchTable = 1, {} mod.filterFunc = function(frame, event, msg, ...) if not msg then return false, msg, ... end for i, v in ipairs(patterns) do msg = gsub(msg, v.pattern, v.matchfunc) end for k,v in pairs(matchTable) do msg = gsub(msg, k, v) matchTable[k] = nil end return false, msg, ... end function mod:RegisterMatch(text) local token = "\255\254\253"..tokennum.."\253\254\255" matchTable[token] = gsub(text, "%%", "%%%%") tokennum = tokennum + 1 return token end end --[[ Popup Box ]]-- local currentLink StaticPopupDialogs["ChatterUrlCopyDialog"] = { text = "URL - Ctrl-C to copy", button2 = CLOSE, hasEditBox = 1, hasWideEditBox = 1, OnShow = function() local editBox = _G[this:GetName().."WideEditBox"] if editBox then editBox:SetText(currentLink) editBox:SetFocus() editBox:HighlightText(0) end local button = _G[this:GetName().."Button2"] if button then button:ClearAllPoints() button:SetWidth(200) button:SetPoint("CENTER", editBox, "CENTER", 0, -30) end end, EditBoxOnEscapePressed = function() this:GetParent():Hide() end, timeout = 0, whileDead = 1, hideOnEscape = 1, maxLetters=1024, -- this otherwise gets cached from other dialogs which caps it at 10..20..30... } local mangleLinkForVoiceChat do --[[ mumble://192.168.1.102:50008?version=1.2.0 mumble://foo:bar@192.168.1.102:50008?version=1.2.0 mumble://:bar@192.168.1.102:50008?version=1.2.0 ]]-- -- Messes with Mumble links to inject our own username. Nifty magical! local function injectCharacterNameForMumble(scheme, connstr) local pre, post = strsplit("@", connstr, 2) local new if post then local user, password = strsplit(":", pre, 2) if password then new = UnitName("player") .. ":" .. password else new = UnitName("player") end new = new .. "@" .. post else new = UnitName("player") .. "@" .. pre end return scheme .. new end local buff = {} local function addTS3Nickname(...) wipe(buff) for i = 1, select("#", ...) do local chunk = select(i, ...) local key, val = strsplit("=", chunk, 2) if val then if strlower(key) ~= "nickname" then tinsert(buff, chunk) end end end if not gotName then local nick = "nickname=" .. UnitName("player") tinsert(buff, nick) end return table.concat(buff, "&") end --[[ ts3server://ts3.hoster.com ts3server://ts3.hoster.com? ts3server://ts3.hoster.com?port=9987& ts3server://ts3.hoster.com?port=9987&nickname=UserNickname&password=serverPassword ]]-- local function injectCharacterNameForTeamspeak(scheme, connstr) local url, query = strsplit("?", connstr, 2) if query then query = addTS3Nickname(strsplit("&", query)) else query = "nickname=" .. UnitName("player") end return scheme .. url .. "?" .. query end function mangleLinkForVoiceChat(text) if mod.db.profile.mangleMumble then text = text:gsub("^(mumble://)([^/?]+)", injectCharacterNameForMumble) end if mod.db.profile.mangleTeamspeak then text = text:gsub("^(ts3server://)(.+)", injectCharacterNameForTeamspeak) end return text end end function mod:SetItemRef(link, text, button) if sub(link, 1, 3) == "url" then currentLink = sub(link, 5) currentLink = mangleLinkForVoiceChat(currentLink) StaticPopup_Show("ChatterUrlCopyDialog") return end return self.hooks.SetItemRef(link, text, button) end function mod:Info() return L["Lets you copy URLs out of chat."] end function mod:GetOptions() return options end tlds = { ONION = true, -- Copied from http://data.iana.org/TLD/tlds-alpha-by-domain.txt -- Version 2008041301, Last Updated Mon Apr 21 08:07:00 2008 UTC AC = true, AD = true, AE = true, AERO = true, AF = true, AG = true, AI = true, AL = true, AM = true, AN = true, AO = true, AQ = true, AR = true, ARPA = true, AS = true, ASIA = true, AT = true, AU = true, AW = true, AX = true, AZ = true, BA = true, BB = true, BD = true, BE = true, BF = true, BG = true, BH = true, BI = true, BIZ = true, BJ = true, BM = true, BN = true, BO = true, BR = true, BS = true, BT = true, BV = true, BW = true, BY = true, BZ = true, CA = true, CAT = true, CC = true, CD = true, CF = true, CG = true, CH = true, CI = true, CK = true, CL = true, CM = true, CN = true, CO = true, COM = true, COOP = true, CR = true, CU = true, CV = true, CX = true, CY = true, CZ = true, DE = true, DJ = true, DK = true, DM = true, DO = true, DZ = true, EC = true, EDU = true, EE = true, EG = true, ER = true, ES = true, ET = true, EU = true, FI = true, FJ = true, FK = true, FM = true, FO = true, FR = true, GA = true, GB = true, GD = true, GE = true, GF = true, GG = true, GH = true, GI = true, GL = true, GM = true, GN = true, GOV = true, GP = true, GQ = true, GR = true, GS = true, GT = true, GU = true, GW = true, GY = true, HK = true, HM = true, HN = true, HR = true, HT = true, HU = true, ID = true, IE = true, IL = true, IM = true, IN = true, INFO = true, INT = true, IO = true, IQ = true, IR = true, IS = true, IT = true, JE = true, JM = true, JO = true, JOBS = true, JP = true, KE = true, KG = true, KH = true, KI = true, KM = true, KN = true, KP = true, KR = true, KW = true, KY = true, KZ = true, LA = true, LB = true, LC = true, LI = true, LK = true, LR = true, LS = true, LT = true, LU = true, LV = true, LY = true, MA = true, MC = true, MD = true, ME = true, MG = true, MH = true, MIL = true, MK = true, ML = true, MM = true, MN = true, MO = true, MOBI = true, MP = true, MQ = true, MR = true, MS = true, MT = true, MU = true, MUSEUM = true, MV = true, MW = true, MX = true, MY = true, MZ = true, NA = true, NAME = true, NC = true, NE = true, NET = true, NF = true, NG = true, NI = true, NL = true, NO = true, NP = true, NR = true, NU = true, NZ = true, OM = true, ORG = true, PA = true, PE = true, PF = true, PG = true, PH = true, PK = true, PL = true, PM = true, PN = true, PR = true, PRO = true, PS = true, PT = true, PW = true, PY = true, QA = true, RE = true, RO = true, RS = true, RU = true, RW = true, SA = true, SB = true, SC = true, SD = true, SE = true, SG = true, SH = true, SI = true, SJ = true, SK = true, SL = true, SM = true, SN = true, SO = true, SR = true, ST = true, SU = true, SV = true, SY = true, SZ = true, TC = true, TD = true, TEL = true, TF = true, TG = true, TH = true, TJ = true, TK = true, TL = true, TM = true, TN = true, TO = true, TP = true, TR = true, TRAVEL = true, TT = true, TV = true, TW = true, TZ = true, UA = true, UG = true, UK = true, UM = true, US = true, UY = true, UZ = true, VA = true, VC = true, VE = true, VG = true, VI = true, VN = true, VU = true, WF = true, WS = true, YE = true, YT = true, YU = true, ZA = true, ZM = true, ZW = true, }