--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 errorCount = 0 local mailCount = 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 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) end function xanAutoMail:MAIL_INBOX_UPDATE() xanAutoMail:Delay("mailInfoText", 0.5, xanAutoMail.UpdateInfoText, true) if currentStatus == "STOP" then return end xanAutoMail:Delay("mailCheckMailUpdate", 0.2, xanAutoMail.CheckMailUpdate) end function xanAutoMail:UI_ERROR_MESSAGE(event, arg1) if currentStatus == "STOP" then return end local stopMailGrab = false if arg1 == ERR_MAIL_DATABASE_ERROR then DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) There was a mailbox database error from the server.") stopMailGrab = true elseif arg1 == ERR_INV_FULL then DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) Your inventory is full.") stopMailGrab = true elseif arg1 == ERR_ITEM_MAX_COUNT then DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) Cannot loot anymore unique items from Mailbox.") end if stopMailGrab then xanAutoMail:StopMailGrab() return end end --this function makes the delay wait until the inbox has decreased in size when we loot something --if we don't do this then the it will continously try to autoloot an item from the same mail --this leads to the ERR_ITEM_NOT_FOUND error. function xanAutoMail:CheckMailUpdate() --check to see if our inbox has decreased by one since we last autolooted local nItem, nTotal = GetInboxNumItems() if nItem <= mailCount - 1 or nTotal == 0 then xanAutoMail:Delay("mailGrabNextItem", 0.2, xanAutoMail.GrabNextMailItem) else xanAutoMail:Delay("mailCheckMailUpdate", 0.2, xanAutoMail.CheckMailUpdate) end 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 10 error checks if nTotal == errorCount or nTotal <= 0 or errorCheckCount > 10 then xanAutoMail:StopMailGrab() return elseif freeSpace() < 1 then xanAutoMail:StopMailGrab() DEFAULT_CHAT_FRAME:AddMessage("xanAutoMail: (ERROR) Your inventory is full.") return elseif nItem <= 0 and nTotal > 0 then --if we still have something to work with then fire in another 60 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 errorCount = 0 mailCount = 0 for i = 1, nItem do local _, _, _, _, money, COD, _, numItems, wasRead, _, _, _, isGM = GetInboxHeaderInfo(i) if money > 0 or (numItems and numItems > 0) and COD <= 0 and not isGM then if wasRead then errorCount = errorCount + 1 else if money > 0 then moneyCount = moneyCount + money end mailCount = GetInboxNumItems() AutoLootMailItem(i) --we looted something so lets wait for next update return end else errorCount = errorCount + 1 end end --if absolutely nothing happened then exit the loop just in case if errorCount <= 0 then xanAutoMail:StopMailGrab() return else --there was an error so lets try to grab again just in case our total = total errors (which could mean all mail has been read) xanAutoMail:Delay("mailGrabNextItem", 0.2, xanAutoMail.GrabNextMailItem) errorCheckCount = errorCheckCount + 1 --this is another emergency stop, don't do more than 10 error checks end end function xanAutoMail:StartMailGrab() if GetInboxNumItems() == 0 then return end currentStatus = "START" inboxAllButton:Disable() moneyCount = 0 errorCount = 0 errorCheckCount = 0 xanAutoMail:Delay("mailGrabNextItem", 0.2, xanAutoMail.GrabNextMailItem) end function xanAutoMail:StopMailGrab(force) 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