--This mod expands the functionality of the auto-name generation of blizzards in game mail system. --Typically it will only auto-fill for names of players in your guild. --This mod will expand it to include all your toons you've logged in as, B.Net Friends, and last 10 recently mailed individuals local DB_PLAYER local DB_RECENT local currentPlayer local currentRealm local origHook = {} local inboxAllButton local inboxInfoText local xanAutoMail = CreateFrame("frame","xanAutoMailFrame",UIParent) xanAutoMail:SetScript("OnEvent", function(self, event, ...) if self[event] then return self[event](self, event, ...) end end) local debugf = tekDebug and tekDebug:GetFrame("xanAutoMail") local function Debug(...) if debugf then debugf:AddMessage(string.join(", ", tostringall(...))) end end --[[------------------------ CORE --------------------------]] function xanAutoMail:PLAYER_LOGIN() currentPlayer = UnitName('player') currentRealm = GetRealmName() --do the db initialization self:StartupDB() --increase the mailbox history lines to 15 SendMailNameEditBox:SetHistoryLines(15) --HOOKS FOR CHARACTER NAME HISTORY --------------------------------- --------------------------------- origHook["SendMailFrame_Reset"] = SendMailFrame_Reset SendMailFrame_Reset = self.SendMailFrame_Reset origHook["MailFrameTab_OnClick"] = MailFrameTab_OnClick MailFrameTab_OnClick = self.MailFrameTab_OnClick origHook["AutoComplete_Update"] = AutoComplete_Update AutoComplete_Update = self.AutoComplete_Update origHook[SendMailNameEditBox] = origHook[SendMailNameEditBox] or {} origHook[SendMailNameEditBox]["OnEditFocusGained"] = SendMailNameEditBox:GetScript("OnEditFocusGained") origHook[SendMailNameEditBox]["OnChar"] = SendMailNameEditBox:GetScript("OnChar") SendMailNameEditBox:SetScript("OnEditFocusGained", self.OnEditFocusGained) SendMailNameEditBox:SetScript("OnChar", self.OnChar) --------------------------------- --------------------------------- --make the open all button inboxAllButton = CreateFrame("Button", "xanAutoMail_OpenAllBTN", InboxFrame, "UIPanelButtonTemplate") inboxAllButton:SetWidth(100) inboxAllButton:SetHeight(20) inboxAllButton:SetPoint("CENTER", InboxFrame, "TOP", -80, -55) inboxAllButton:SetText("Open All") inboxAllButton:SetScript("OnClick", function() xanAutoMail.StartMailGrab() end) inboxInfoText = InboxFrame:CreateFontString("xanAutoMail_InfoText", "ARTWORK", "GameFontNormalSmall") inboxInfoText:SetJustifyH("LEFT") inboxInfoText:SetFontObject("GameFontNormal") inboxInfoText:SetPoint("TOPLEFT", inboxAllButton, "TOPRIGHT", 5, -5) self:UnregisterEvent("PLAYER_LOGIN") self.PLAYER_LOGIN = nil end function xanAutoMail:StartupDB() xanAutoMailDB = xanAutoMailDB or {} xanAutoMailDB[currentRealm] = xanAutoMailDB[currentRealm] or {} --player list xanAutoMailDB[currentRealm]["player"] = xanAutoMailDB[currentRealm]["player"] or {} DB_PLAYER = xanAutoMailDB[currentRealm]["player"] --recent list xanAutoMailDB[currentRealm]["recent"] = xanAutoMailDB[currentRealm]["recent"] or {} DB_RECENT = xanAutoMailDB[currentRealm]["recent"] --check for current user if DB_PLAYER[currentPlayer] == nil then DB_PLAYER[currentPlayer] = true end end --------------------------------------------------- ---------------CHARACTER NAME DB ------------------ --------------------------------------------------- --This is called when mailed is sent function xanAutoMail:SendMailFrame_Reset() --first lets get the playername local playerName = strtrim(SendMailNameEditBox:GetText()) --if we don't have something to work with then call original function if string.len(playerName) < 1 then return origHook["SendMailFrame_Reset"]() end --add the name to the history SendMailNameEditBox:AddHistoryLine(playerName) --add the name to our recent DB, first check to see if it's already there --if so then remove it, otherwise add it to the top of the list and remove the 11 entry from the table. --afterwards call the original function for k = 1, #DB_RECENT do if playerName == DB_RECENT[k] then tremove(DB_RECENT, k) break end end tinsert(DB_RECENT, 1, playerName) for k = #DB_RECENT, 11, -1 do tremove(DB_RECENT, k) end origHook["SendMailFrame_Reset"]() -- set the name to the auto fill SendMailNameEditBox:SetText(playerName) SendMailNameEditBox:HighlightText() end --this is called when one of the mailtabs is clicked --we have to autofill the name when the tabs are clicked function xanAutoMail:MailFrameTab_OnClick(tab) origHook["MailFrameTab_OnClick"](self, tab) if tab == 2 then local playerName = DB_RECENT[1] if playerName and SendMailNameEditBox:GetText() == "" then SendMailNameEditBox:SetText(playerName) SendMailNameEditBox:HighlightText() end end end --this function is called each time a character is pressed in the playername field of the mail window function xanAutoMail:OnChar(...) if self:GetUTF8CursorPosition() ~= strlenutf8(self:GetText()) then return end local text = strupper(self:GetText()) local textlen = strlen(text) local foundName --check player toons for k, v in pairs(DB_PLAYER) do if strfind(strupper(k), text, 1, 1) == 1 then foundName = k break end end --check our recent list if not foundName then for k = 1, #DB_RECENT do local playerName = DB_RECENT[k] if strfind(strupper(playerName), text, 1, 1) == 1 then foundName = playerName break end end end --Check our RealID friends if not foundName then local numBNetTotal, numBNetOnline = BNGetNumFriends() for i = 1, numBNetOnline do local presenceID, givenName, surname, toonName, toonID, client = BNGetFriendInfo(i) if (toonName and client == BNET_CLIENT_WOW and CanCooperateWithToon(toonID)) then if strfind(strupper(toonName), text, 1, 1) == 1 then foundName = toonName break end end end end --call the original onChar to display the dropdown origHook[SendMailNameEditBox]["OnChar"](self, ...) --if we found a name then override the one in the editbox if foundName then self:SetText(foundName) self:HighlightText(textlen, -1) self:SetCursorPosition(textlen) end end function xanAutoMail:OnEditFocusGained(...) SendMailNameEditBox:HighlightText() end function xanAutoMail:AutoComplete_Update(editBoxText, utf8Position, ...) if self ~= SendMailNameEditBox then origHook["AutoComplete_Update"](self, editBoxText, utf8Position, ...) end end --------------------------------------------------- --------------------------------------------------- --------------------------------------------------- --[[------------------------ OPEN ALL MAIL --------------------------]] local delayCount = {} local moneyCount = 0 local skipCount = 0 local errorCheckCount = 0 local currentStatus = "STOP" xanAutoMail:RegisterEvent("MAIL_CLOSED") xanAutoMail:RegisterEvent("MAIL_SHOW") xanAutoMail:RegisterEvent("MAIL_INBOX_UPDATE") xanAutoMail:RegisterEvent("UI_ERROR_MESSAGE") local function colorMoneyText(value) if not value then return "" end local gold = abs(value / 10000) local silver = abs(mod(value / 100, 100)) local copper = abs(mod(value, 100)) local GOLD_ABRV = "g" local SILVER_ABRV = "s" local COPPER_ABRV = "c" local WHITE = "ffffff" local COLOR_COPPER = "eda55f" local COLOR_SILVER = "c7c7cf" local COLOR_GOLD = "ffd700" if value >= 10000 or value <= -10000 then return format("|cff%s%d|r|cff%s%s|r |cff%s%d|r|cff%s%s|r |cff%s%d|r|cff%s%s|r", WHITE, gold, COLOR_GOLD, GOLD_ABRV, WHITE, silver, COLOR_SILVER, SILVER_ABRV, WHITE, copper, COLOR_COPPER, COPPER_ABRV) elseif value >= 100 or value <= -100 then return format("|cff%s%d|r|cff%s%s|r |cff%s%d|r|cff%s%s|r", WHITE, silver, COLOR_SILVER, SILVER_ABRV, WHITE, copper, COLOR_COPPER, COPPER_ABRV) else return format("|cff%s%d|r|cff%s%s|r", WHITE, copper, COLOR_COPPER, COPPER_ABRV) end end local function freeSpace() local totalFree = 0 for i=0, NUM_BAG_SLOTS do local numberOfFreeSlots = GetContainerNumFreeSlots(i) totalFree = totalFree + numberOfFreeSlots end return totalFree end local function inboxFullCheck() --sometimes the mailbox is full, if this happens we have to make changes to the button position local nItem, nTotal = GetInboxNumItems() if nItem and nTotal then if ( nTotal > nItem) or InboxTooMuchMail:IsVisible() and not inboxAllButton.movedBottom then inboxAllButton:ClearAllPoints() inboxAllButton:SetPoint("CENTER", InboxFrame, "BOTTOM", -60, 100) inboxAllButton.movedBottom = true inboxInfoText:ClearAllPoints() inboxInfoText:SetPoint("TOPLEFT", inboxAllButton, "TOPRIGHT", 5, -5) elseif (( nTotal < nItem) or not InboxTooMuchMail:IsVisible()) and inboxAllButton.movedBottom then inboxAllButton.movedBottom = nil inboxAllButton:ClearAllPoints() inboxAllButton:SetPoint("CENTER", InboxFrame, "TOP", -80, -55) inboxInfoText:ClearAllPoints() inboxInfoText:SetPoint("TOPLEFT", inboxAllButton, "TOPRIGHT", 5, -5) end end end xanAutoMail:SetScript("OnUpdate", function( self, elapsed ) if #delayCount > 0 then for i = #delayCount, 1, -1 do if delayCount[i].endTime and delayCount[i].endTime <= GetTime() then local func = delayCount[i].callbackFunction tremove(delayCount, i) func() end end end end ) function xanAutoMail:Delay(name, duration, callbackFunction, force) if not force and currentStatus == "STOP" then return end for k, q in ipairs(delayCount) do if q.name == name then --don't run the same delay more than once, we can however refresh it q.duration = duration q.endTime = (GetTime()+duration) q.callbackFunction = callbackFunction return end end tinsert(delayCount, {name=name, duration=duration, endTime=(GetTime()+duration), callbackFunction=callbackFunction}) end function xanAutoMail:UpdateInfoText() local nItem, nTotal = GetInboxNumItems() if nTotal == nItem then inboxInfoText:SetText(format("Showing all %d mail.", nItem)) else inboxInfoText:SetText(format("Showing %d of %d mail.", nItem, nTotal)) end --hide the stupid icon if necessary if nTotal <= 0 and MiniMapMailFrame:IsVisible() then MiniMapMailFrame:Hide() end end function xanAutoMail:MAIL_SHOW() inboxFullCheck() CheckInbox() inboxInfoText:SetText("Waiting...") xanAutoMail:Delay("mailInfoText", 0.5, xanAutoMail.UpdateInfoText, true) end function xanAutoMail:MAIL_CLOSED() xanAutoMail:StopMailGrab(true, 1) end function xanAutoMail:MAIL_INBOX_UPDATE() xanAutoMail:Delay("mailInfoText", 0.5, xanAutoMail.UpdateInfoText, true) if currentStatus == "STOP" then return end --keep increasing the delay before the next mail grab until all items are taken from current opened mail xanAutoMail:Delay("mailGrabNextItem", 0.5, xanAutoMail.GrabNextMailItem) end function xanAutoMail:UI_ERROR_MESSAGE(event, num, msg) if currentStatus == "STOP" then return end local stopMailGrab = false if msg == ERR_MAIL_DATABASE_ERROR then DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) There was a mailbox database error from the server.") stopMailGrab = true elseif msg == ERR_INV_FULL then DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) Your inventory is full.") stopMailGrab = true elseif msg == ERR_ITEM_MAX_COUNT then DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) Cannot loot anymore unique items from Mailbox.") DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: Please the delete item(s) from the Mailbox before trying again.") stopMailGrab = true end if stopMailGrab then xanAutoMail:StopMailGrab(false, 2) return end end function xanAutoMail:IsMailItemEmpty(index) local packageIcon, stationeryIcon, sender, subject, money, COD, daysLeft, numItems, wasRead, wasReturned, textCreated, canReply, isGM, itemQuantity = GetInboxHeaderInfo(index) if isGM then return false end if canReply then return false end if numItems then return false end if COD > 0 then return false end if money > 0 then return false end if wasReturned then return false end return true end function xanAutoMail:GrabNextMailItem() if currentStatus == "STOP" then return end --do inbox check if currentStatus == "CHECK" then CheckInbox() currentStatus = "SKIPCHECK" xanAutoMail:Delay("mailGrabNextItem", 0.5, xanAutoMail.GrabNextMailItem) return end local nItem, nTotal = GetInboxNumItems() xanAutoMail:UpdateInfoText() --check to see if the last messages were read or if we have nothing to work with, or we have done more than 50 error checks, which is roughly about 10 to 11 seconds if nTotal <= 0 or skipCount >= nTotal or errorCheckCount > 50 then if errorCheckCount > 50 then DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) Mailbox latency error. (Try Again)") end xanAutoMail:StopMailGrab(false, 4) return elseif freeSpace() < 1 then xanAutoMail:StopMailGrab(false, 5) DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) Your inventory is full.") return elseif (nItem <= 0 or skipCount >= nItem) and nTotal > 0 then --if we still have something to work with then fire in another 45 seconds currentStatus = "CHECK" errorCheckCount = 0 xanAutoMail:Delay("mailInboxCheck", 45, xanAutoMail.GrabNextMailItem) inboxInfoText:SetText("Waiting 45 seconds") DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: Waiting 45 seconds for next mail batch.") return end skipCount = 0 --reset for mIndex = nItem, 1, -1 do local _, _, _, _, money, COD, _, numItems, wasRead, _, _, _, isGM = GetInboxHeaderInfo(mIndex) if money > 0 or (numItems and numItems > 0) and COD <= 0 and not isGM then if money > 0 then moneyCount = moneyCount + money end TakeInboxMoney(mIndex) AutoLootMailItem(mIndex) --we looted something so lets wait for next update xanAutoMail:Delay("mailGrabNextItem", 0.5, xanAutoMail.GrabNextMailItem) --just in case return end if xanAutoMail:IsMailItemEmpty(mIndex) then DeleteInboxItem(mIndex) xanAutoMail:Delay("mailGrabNextItem", 0.5, xanAutoMail.GrabNextMailItem) --just in case return end skipCount = skipCount + 1 end xanAutoMail:Delay("mailGrabNextItem", 0.2, xanAutoMail.GrabNextMailItem) errorCheckCount = errorCheckCount + 1 end function xanAutoMail:StartMailGrab() if GetInboxNumItems() == 0 then return end currentStatus = "START" inboxAllButton:Disable() moneyCount = 0 skipCount = 0 errorCheckCount = 0 xanAutoMail:Delay("mailGrabNextItem", 0.2, xanAutoMail.GrabNextMailItem) end function xanAutoMail:StopMailGrab(force, flag) currentStatus = "STOP" delayCount = {} inboxAllButton:Enable() if not force then if moneyCount > 0 then DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: Total money from mailbox ["..colorMoneyText(moneyCount).."]") end CheckInbox() xanAutoMail:Delay("mailInfoText", 0.5, xanAutoMail.UpdateInfoText, true) end end if IsLoggedIn() then xanAutoMail:PLAYER_LOGIN() else xanAutoMail:RegisterEvent("PLAYER_LOGIN") end