-- ------------------------------------------------------------------------------ -- -- TradeSkillMaster_Mailing -- -- http://www.curse.com/addons/wow/tradeskillmaster_mailing -- -- -- -- A TradeSkillMaster Addon (http://tradeskillmaster.com) -- -- All Rights Reserved* - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- local TSM = select(2, ...) local Inbox = TSM:NewModule("Inbox", "AceEvent-3.0", "AceHook-3.0") local L = LibStub("AceLocale-3.0"):GetLocale("TradeSkillMaster_Mailing") -- loads the localization table local private = { recheckTime = 1, allowTimerStart = true, lootIndex = 1, freeSlots = true } function Inbox:OnEnable() Inbox:RegisterEvent("MAIL_SHOW") TSMAPI:CreateEventBucket("MAIL_INBOX_UPDATE", private.InboxUpdate, 0.3) Inbox:RegisterEvent("MAIL_CLOSED") end function Inbox:CreateTab(parent) local frame = CreateFrame("Frame", nil, parent) frame:Hide() frame:SetAllPoints() frame:SetScript("OnHide", function() private:StopAutoLooting() end) frame:SetScript("OnShow", private.InboxUpdate) local label = TSMAPI.GUI:CreateLabel(frame, "small") label:SetPoint("TOPLEFT", 5, -5) label:SetPoint("TOPRIGHT", -5, -5) label:SetHeight(15) label:SetJustifyH("CENTER") label:SetJustifyV("CENTER") frame.topLabel = label TSMAPI.GUI:CreateHorizontalLine(frame, -25) local stContainer = CreateFrame("Frame", nil, frame) stContainer:SetPoint("TOPLEFT", 5, -35) stContainer:SetPoint("BOTTOMRIGHT", -5, 55) TSMAPI.Design:SetFrameColor(stContainer) local handlers = { OnClick = function(_, data) if IsShiftKeyDown() and select(6, GetInboxHeaderInfo(data.index)) <= 0 then if private:CanLootMailIndex(data.index) then private:LootMailItem(data.index) else TSM:Print(L["Could not loot item from mail because your bags are full."]) end end if InboxFrame.openMailID ~= data.index then InboxFrame.openMailID = data.index OpenMailFrame.updateButtonPositions = true OpenMail_Update() ShowUIPanel(OpenMailFrame) OpenMailFrame:SetPoint("TOPLEFT", InboxFrame, "TOPRIGHT", 32, 0) PlaySound("igSpellBookOpen") else InboxFrame.openMailID = 0 HideUIPanel(OpenMailFrame) end InboxFrame_Update() end, OnEnter = function(_, data, self) end, OnLeave = function() end, } local st = TSMAPI:CreateScrollingTable(stContainer, nil, handlers) st:SetData({}) frame.st = st local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", 5, 30) btn:SetPoint("BOTTOMRIGHT", -5, 30) btn:SetHeight(20) btn:SetText(L["Open All Mail"]) btn:SetScript("OnClick", function() private:StartAutoLooting("all") end) frame.allBtn = btn local label = TSMAPI.GUI:CreateLabel(frame, "normal") label:SetPoint("BOTTOMLEFT", 5, 5) label:SetHeight(20) label:SetJustifyH("LEFT") label:SetJustifyV("CENTER") label:SetText(L["AH Mail:"]) local btnWidth = (frame:GetWidth() - label:GetWidth() - 25) / 5 local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", label, "BOTTOMRIGHT", 5, 0) btn:SetWidth(btnWidth) btn:SetHeight(20) btn:SetText(L["Sales"]) btn:SetScript("OnClick", function() private:StartAutoLooting("sales") end) frame.salesBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", frame.salesBtn, "BOTTOMRIGHT", 5, 0) btn:SetWidth(btnWidth) btn:SetHeight(20) btn:SetText(L["Buys"]) btn:SetScript("OnClick", function() private:StartAutoLooting("buys") end) frame.buysBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", frame.buysBtn, "BOTTOMRIGHT", 5, 0) btn:SetWidth(btnWidth) btn:SetHeight(20) btn:SetText(L["Cancels"]) btn:SetScript("OnClick", function() private:StartAutoLooting("cancels") end) frame.cancelsBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", frame.cancelsBtn, "BOTTOMRIGHT", 5, 0) btn:SetWidth(btnWidth) btn:SetHeight(20) btn:SetText(L["Expires"]) btn:SetScript("OnClick", function() private:StartAutoLooting("expires") end) frame.expiresBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 18) btn:SetPoint("BOTTOMLEFT", frame.expiresBtn, "BOTTOMRIGHT", 5, 0) btn:SetPoint("BOTTOMRIGHT", -5, 5) btn:SetHeight(20) btn:SetText("Pending") btn:SetScript("OnClick", function() private:StartAutoLooting("pendings") end) frame.expiresBtn = btn local btn = TSMAPI.GUI:CreateButton(frame, 16) btn:SetFrameStrata("HIGH") btn:SetPoint("CENTER") btn:SetHeight(30) btn:SetWidth(150) btn:SetText(L["Reload UI"]) btn:SetScript("OnClick", ReloadUI) btn:Hide() frame.reloadBtn = btn frame.EnableButtons = function(self) self.allBtn:Enable() self.salesBtn:Enable() self.buysBtn:Enable() self.cancelsBtn:Enable() self.expiresBtn:Enable() self.buttonsEnabled = true end frame.DisableButtons = function(self) self.allBtn:Disable() self.salesBtn:Disable() self.buysBtn:Disable() self.cancelsBtn:Disable() self.expiresBtn:Disable() self.buttonsEnabled = nil end frame.buttonsEnabled = true private.frame = frame return frame end local function CacheFrameOnUpdate(self, elapsed) if not private.waitingForData then local seconds = self.endTime - GetTime() if seconds <= 0 then -- Look for new mail -- Sometimes it fails and isn't available at exactly 60-61 seconds, and more like 62-64, will keep rechecking every 1 second -- until data becomes available if TSM.db.global.autoCheck then private.waitingForData = true self.timeLeft = private.recheckTime private.lootIndex = 1 private.resetIndex = nil CheckInbox() private.frame.reloadBtn:Hide() else self:Hide() end return end private:UpdateTopLabel() else self.timeLeft = self.timeLeft - elapsed if self.timeLeft <= 0 then self.timeLeft = private.recheckTime private.lootIndex = 1 private.resetIndex = nil CheckInbox() private.frame.reloadBtn:Hide() end end end function Inbox:MAIL_SHOW() if not private.cacheFrame then -- Timer for mailbox cache updates private.cacheFrame = CreateFrame("Frame", nil, MailFrame) private.cacheFrame:Hide() private.cacheFrame:SetScript("OnUpdate", CacheFrameOnUpdate) end end local function FormatDaysLeft(daysLeft, index) -- code taken from Blizzard MailFrame.lua code if daysLeft >= 1 then if InboxItemCanDelete(index) then daysLeft = YELLOW_FONT_COLOR_CODE .. format(DAYS_ABBR, floor(daysLeft)) .. " " .. FONT_COLOR_CODE_CLOSE; else daysLeft = GREEN_FONT_COLOR_CODE .. format(DAYS_ABBR, floor(daysLeft)) .. " " .. FONT_COLOR_CODE_CLOSE; end else daysLeft = RED_FONT_COLOR_CODE .. SecondsToTime(floor(daysLeft * 24 * 60 * 60)) .. FONT_COLOR_CODE_CLOSE; end return daysLeft end function private:UpdateTopLabel() local parts = {} local numMail, totalMail = GetInboxNumItems() if totalMail == numMail then tinsert(parts, format(L["Showing all %d mail."], numMail)) else tinsert(parts, format(L["Showing %d of %d mail."], numMail, totalMail)) end local collectGold = private.collectGold or 0 if collectGold > 0 then tinsert(parts, format(L["%s to collect."], TSMAPI:FormatTextMoney(collectGold))) end local nextRefresh = private.cacheFrame:IsVisible() and private.cacheFrame.endTime if nextRefresh then if numMail == 0 and TSM.db.global.showReloadBtn then private.frame.reloadBtn:Show() end tinsert(parts, format(L["Next inbox update in %d seconds."], max(ceil(nextRefresh - GetTime()), 0))) end private.frame.topLabel:SetText(table.concat(parts, " ")) end function private:InboxUpdate() if not private.frame or not private.frame:IsVisible() then return end TSMAPI:CancelFrame("inboxLootTextDelay") local numMail, totalMail = GetInboxNumItems() local greenColor, redColor, yellowColor = "|cff00ff00", "|cffff0000", "|cffeeff00" local mailInfo = {} local collectGold = 0 for i = 1, numMail do mailInfo[i] = "" local isInvoice = select(4, GetInboxText(i)) --local _, _, sender, subject, money, cod, _, hasItem = GetInboxHeaderInfo(index) local _, _, sender, subject, money, cod, daysLeft, hasItem, _, _, _, _, _, itemQuantity = GetInboxHeaderInfo(i) if isInvoice then local invoiceType, itemName, playerName, bid, buyout, deposit, ahcut, _, _, _, quantity = GetInboxInvoiceInfo(i) sender = sender or "?" if sender == "Blackwater Auction House" then sender = "AH" end if not quantity then quantity = select(3, GetInboxItem(i)) end -- fix MoP difference if invoiceType == "buyer" then local itemLink = GetInboxItemLink(i, 1) or itemName mailInfo[i] = format(L["Buy: %s (%d) | %s | %s"], itemLink, quantity or 1, TSMAPI:FormatTextMoney(bid, redColor), FormatDaysLeft(daysLeft, i)) elseif invoiceType == "seller" then collectGold = collectGold + bid - ahcut mailInfo[i] = format(L["Sale: %s (%d) | %s | %s"], itemName, quantity or 1, TSMAPI:FormatTextMoney(bid - ahcut, greenColor), FormatDaysLeft(daysLeft, i)) -- mailInfo[i] = format("Sale: %s | %s | %s", itemName, TSMAPI:FormatTextMoney(bid - ahcut, greenColor), FormatDaysLeft(daysLeft, i)) elseif invoiceType == "seller_temp_invoice" then mailInfo[i] = format("Pending Sale: %s (%d) | %s | %s", itemName, quantity or 1, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor), FormatDaysLeft(daysLeft, i)) -- mailInfo[i] = format("Pending Sale: %s | %s | %s", itemName, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor), FormatDaysLeft(daysLeft, i)) end elseif hasItem then local itemLink local quantity = 0 for j = 1, hasItem do local link = GetInboxItemLink(i, j) itemLink = itemLink or link quantity = quantity + select(3, GetInboxItem(i, j)) if TSMAPI:GetItemString(itemLink) ~= TSMAPI:GetItemString(link) then itemLink = L["Multiple Items"] quantity = -1 break end end local itemDesc = (quantity > 0 and format("%s (%d)", itemLink, quantity)) or (quantity == -1 and L["Multiple Items"]) or "---" if hasItem == 1 and itemLink and strfind(subject, "^" .. TSMAPI:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, TSMAPI:GetSafeItemInfo(itemLink)))) then mailInfo[i] = format(L["Expired: %s | %s"], itemDesc, FormatDaysLeft(daysLeft, i)) elseif cod > 0 then mailInfo[i] = format(L["COD: %s | %s | %s | %s"], itemDesc, TSMAPI:FormatTextMoney(cod, redColor), sender or "---", FormatDaysLeft(daysLeft, i)) elseif money > 0 then collectGold = collectGold + money mailInfo[i] = format("%s + %s | %s | %s", itemDesc, TSMAPI:FormatTextMoney(money, greenColor), sender or "---", FormatDaysLeft(daysLeft, i)) else mailInfo[i] = format("%s | %s | %s", itemDesc, sender or "---", FormatDaysLeft(daysLeft, i)) end elseif money > 0 then mailInfo[i] = format("%s | %s | %s | %s", subject, TSMAPI:FormatTextMoney(money, greenColor), sender or "---", FormatDaysLeft(daysLeft, i)) else mailInfo[i] = format("%s | %s | %s", subject, sender or "---", FormatDaysLeft(daysLeft, i)) end end private.collectGold = collectGold local stData = {} for i, info in ipairs(mailInfo) do tinsert(stData, { cols = { { value = info } }, index = i }) end private.frame.st:SetData(stData) private:UpdateTopLabel() -- -- Yay nothing else to loot, so nothing else to update the cache for! -- if private.cacheFrame.endTime and numMail == totalMail and private.lastTotal ~= totalMail then -- private.cacheFrame.endTime = nil -- private.cacheFrame:Hide() -- -- Start a timer since we're over the limit of 50 items before waiting for it to recache -- elseif (private.cacheFrame.endTime and numMail >= 50 and private.lastTotal ~= totalMail) or (numMail >= 50 and private.allowTimerStart) then -- private.resetIndex = nil -- private.allowTimerStart = nil -- private.waitingForData = nil -- private.lastTotal = totalMail -- private.cacheFrame.endTime = GetTime() + 60 -- private.cacheFrame:Show() -- end -- The last item we setup to auto loot is finished, time for the next one if not private.frame.buttonsEnabled then -- if private.autoLootTotal ~= numMail then -- private.autoLootTotal = GetInboxNumItems() -- If we're auto checking mail when new data is available, will wait and continue auto looting, otherwise we just stop now if totalMail == 0 then private:StopAutoLooting() else private:AutoLoot() end else TSMAPI:CreateTimeDelay("mailSkipDelay", 1, function() local money, _, _, hasItem, _, _, _, canReply = select(5, GetInboxHeaderInfo(private.lootIndex)) if not hasItem and money == 0 then private.lootIndex = private.lootIndex + 1 return private:AutoLoot() end end) -- end end end function private:ShouldOpenMail(index) local shouldOpen if private.mode == "all" then return true elseif private.mode == "sales" then local money = select(5, GetInboxHeaderInfo(index)) if money > 0 and GetInboxInvoiceInfo(index) == "seller" then return true end elseif private.mode == "buys" then local hasItem = select(8, GetInboxHeaderInfo(index)) if hasItem and GetInboxInvoiceInfo(index) == "buyer" then return true end elseif private.mode == "cancels" then local isInvoice = select(4, GetInboxText(index)) local subject, _, _, _, hasItem = select(4, GetInboxHeaderInfo(index)) if not isInvoice and hasItem == 1 then local itemLink = GetInboxItemLink(index, 1) if itemLink then local itemName = TSMAPI:GetSafeItemInfo(itemLink) local quantity = select(3, GetInboxItem(index, 1)) if quantity and quantity > 0 and (subject == format(AUCTION_REMOVED_MAIL_SUBJECT.." (%d)", itemName, quantity) or subject == format(AUCTION_REMOVED_MAIL_SUBJECT, itemName)) then return true end end end elseif private.mode == "pendings" then local isInvoice = select(4, GetInboxText(index)) if isInvoice then invoiceType = GetInboxInvoiceInfo(index) if invoiceType == "seller_temp_invoice" then return true end end elseif private.mode == "expires" then local isInvoice = select(4, GetInboxText(index)) local subject, _, _, _, hasItem = select(4, GetInboxHeaderInfo(index)) if not isInvoice and hasItem == 1 then local itemLink = GetInboxItemLink(index, 1) if itemLink and strfind(subject, "^" .. TSMAPI:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, TSMAPI:GetSafeItemInfo(itemLink)))) then return true end end end end -- Deals with auto looting of mail! function private:StartAutoLooting(mode) private.mode = mode local canCollectMail if private.mode == "all" then local total private.autoLootTotal, total = GetInboxNumItems() canCollectMail = not (private.autoLootTotal == 0 and total == 0) else for i = 1, GetInboxNumItems() do if private:ShouldOpenMail(i) then canCollectMail = true break end end end if not canCollectMail then private.mode = nil return end Inbox:RegisterEvent("UI_ERROR_MESSAGE") private.frame:DisableButtons() private.moneyCollected = 0 private.mode = mode private.lootIndex = 1 private:AutoLoot() end function private:AutoLoot() TSMAPI:CancelFrame("mailSkipDelay") -- Already looted everything after the invalid indexes we had, so fail it if private.lootIndex > 1 and private.lootIndex > GetInboxNumItems() then if private.resetIndex then private:StopAutoLooting() else private.resetIndex = true private.lootIndex = 1 private:AutoLoot() end return end local _, _, sender, subject, money, cod, _, items, _, _, _, _, isGM = GetInboxHeaderInfo(private.lootIndex) if (sender == "The Postmaster" or sender == "Blackwater Auction House" or sender == "Customer Support") or not isGM and (not cod or cod <= 0) and ((money and money > 0) or (items and items > 0)) or GetInboxInvoiceInfo(private.lootIndex) == "seller_temp_invoice" then TSMAPI:CancelFrame("mailWaitDelay") if private.mode == "all" then if money > 0 then if TSM.db.global.openAllLeaveGold then private.lootIndex = private.lootIndex + 1 return private:AutoLoot() end end if private:CanLootMailIndex(private.lootIndex) then if money > 0 then private.moneyCollected = private.moneyCollected + money end private:LootMailItem(private.lootIndex) else private.lootIndex = private.lootIndex + 1 return private:AutoLoot() end else if private:CanLootMailIndex(private.lootIndex) and private:ShouldOpenMail(private.lootIndex) then if money > 0 then private.moneyCollected = private.moneyCollected + money end private:LootMailItem(private.lootIndex) else private.lootIndex = private.lootIndex + 1 return private:AutoLoot() end end -- Can't grab the first mail, so increase it and try again elseif GetInboxNumItems() >= private.lootIndex then private.lootIndex = private.lootIndex + 1 private:AutoLoot() end end function private:LootMailItem(index) if TSM.db.global.inboxMessages then --local _, _, sender, subject, money, cod, _, hasItem = GetInboxHeaderInfo(index) local _, _, sender, subject, money, cod, daysLeft, hasItem, _, _, _, _, _, itemQuantity = GetInboxHeaderInfo(index) sender = sender or "?" isTakeable = select(4, GetInboxText(index)) if isTakeable then -- it's an invoice local invoiceType, itemName, playerName, bid, _, _, ahcut, _, _, _, quantity = GetInboxInvoiceInfo(index) -- fix MoP difference if not quantity then quantity = select(3, GetInboxItem(index)) end local redColor = "|cffFF0000" local greenColor = "|cff00FF00" local yellowColor = "|cffFFFF00" if invoiceType == "buyer" then local itemLink = GetInboxItemLink(index, 1) or itemName TSM:Printf(L["Collected purchase of %s (%d) for %s."], itemLink, quantity or 1, TSMAPI:FormatTextMoney(bid, redColor)) elseif invoiceType == "seller" then TSM:Printf(L["Collected sale of %s (%d) for %s."], itemName, quantity or 1, TSMAPI:FormatTextMoney(bid - ahcut, greenColor)) -- TSM:Printf("Collected sale of %s for %s.", itemName, TSMAPI:FormatTextMoney(bid - ahcut, greenColor)) elseif invoiceType == "seller_temp_invoice" then -- TSM:Printf("Removing pending sale: %s (%s)", itemName, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor)) TSM:Printf("Removing pending sale of %s (%d) for %s.", itemName, quantity or 1, TSMAPI:FormatTextMoney(bid - ahcut, yellowColor)) DeleteInboxItem(index) return end elseif hasItem then local itemLink local quantity = 0 for i = 1, hasItem do local link = GetInboxItemLink(index, i) itemLink = itemLink or link quantity = quantity + select(3, GetInboxItem(index, i)) if TSMAPI:GetItemString(itemLink) ~= TSMAPI:GetItemString(link) then itemLink = L["Multiple Items"] quantity = -1 break end end local itemDesc = (quantity > 0 and format("%s (%d)", itemLink, quantity)) or (quantity == -1 and "Multiple Items") or "?" if hasItem == 1 and itemLink and strfind(subject, "^" .. TSMAPI:StrEscape(format(AUCTION_EXPIRED_MAIL_SUBJECT, TSMAPI:GetSafeItemInfo(itemLink)))) then TSM:Printf(L["Collected expired auction of %s"], itemDesc) elseif cod > 0 then TSM:Printf(L["Collected COD of %s from %s for %s."], itemDesc, sender, TSMAPI:FormatTextMoney(cod, redColor)) elseif money > 0 then TSM:Printf(L["Collected %s and %s from %s."], itemDesc, TSMAPI:FormatTextMoney(money, greenColor), sender) else TSM:Printf(L["Collected %s from %s."], itemDesc, sender) end elseif money > 0 then TSM:Printf(L["Collected %s from %s."], TSMAPI:FormatTextMoney(money, greenColor), sender) elseif (sender == "The Postmaster" or sender == "Blackwater Auction House" or sender == "Customer Support" and subject == "Your Ascension Order" and daysLeft < 270) and money == 0 and hasItem == nil then TSM:Printf("Removing empty mail from %s.", sender) DeleteInboxItem(index) else TSM:Printf(L["Collected mail from %s with a subject of '%s'."], sender, subject) end end AutoLootMailItem(index) end function private:CanLootMailIndex(index) local hasItem = select(8, GetInboxHeaderInfo(index)) if not hasItem or hasItem == 0 then return true end if not TSM.db.global.keepMailSpace or TSM.db.global.keepMailSpace == 0 then for j = 1, ATTACHMENTS_MAX_RECEIVE do local itemString = TSMAPI:GetItemString(GetInboxItemLink(index, j)) local quantity = select(3, GetInboxItem(index, j)) local space = 0 if itemString then for bag = 0, NUM_BAG_SLOTS do if TSMAPI:ItemWillGoInBag(itemString, bag) then for slot = 1, GetContainerNumSlots(bag) do local iString = TSMAPI:GetItemString(GetContainerItemLink(bag, slot)) if iString == itemString then local stackSize = select(2, GetContainerItemInfo(bag, slot)) local maxStackSize = select(8, TSMAPI:GetSafeItemInfo(itemString)) if (maxStackSize - stackSize) >= quantity then return true end elseif not iString then return true end end end end end end else -- get number of free slots per generic / special bags and partial slots by bag local genericSpace, uniqueSpace, partSlots = private:GetBagSlots() local usedSlots = {} for j = 1, ATTACHMENTS_MAX_RECEIVE do local itemString = TSMAPI:GetItemString(GetInboxItemLink(index, j)) local quantity = select(3, GetInboxItem(index, j)) local isDone = false if itemString then for bag = 0, NUM_BAG_SLOTS do if TSMAPI:ItemWillGoInBag(itemString, bag) then for slot = 1, GetContainerNumSlots(bag) do local iString = TSMAPI:GetItemString(GetContainerItemLink(bag, slot)) if iString == itemString and (partSlots[bag] and partSlots[bag][slot]) then local stackSize = select(2, GetContainerItemInfo(bag, slot)) local maxStackSize = select(8, TSMAPI:GetSafeItemInfo(itemString)) if (maxStackSize - stackSize - (usedSlots[bag] and usedSlots[bag][slot] or 0)) >= quantity then if stackSize + quantity == maxStackSize then if partSlots[bag] and partSlots[bag][slot] then partSlots[bag][slot] = nil -- this partial slot would be filled so remove it from available part slots end else if not usedSlots[bag] then usedSlots[bag] = {} end usedSlots[bag][slot] = (usedSlots[bag][slot] or 0) + stackSize -- store the stacksize for this slot after adding this item end isDone = true break end else local itemFamily = GetItemFamily(itemString) local bagFamily = GetItemFamily(GetBagName(bag)) or 0 if itemFamily and bagFamily and bagFamily > 0 and bit.band(itemFamily, bagFamily) > 0 and (uniqueSpace[bag] and uniqueSpace[bag] > 0) then uniqueSpace[bag] = uniqueSpace[bag] - 1 -- remove one empty slot from the bag isDone = true break else if genericSpace[bag] and genericSpace[bag] > 0 then genericSpace[bag] = genericSpace[bag] - 1 -- remove one empty slot from the bag if genericSpace[bag] <= 0 then genericSpace[bag] = nil end isDone = true break end end end end if isDone then break end end end end end --calculate the total remaining empty slots in generic bags after looting this mail local remainingSpace = 0 for bag, space in pairs(genericSpace) do remainingSpace = remainingSpace + space end if remainingSpace >= TSM.db.global.keepMailSpace then return true -- either not using keepMailSpace option or we can loot all of this mail else private.keepFreeSlots = true -- can't loot the whole of this mail and leave enough free slots so set the flag that displays the chat message end end end function private:StopAutoLooting(failed) if failed and (not private.frame or not private.frame:IsVisible()) then TSM:Print(L["Cannot finish auto looting, inventory is full or too many unique items."]) end if private.keepFreeSlots then TSM:Printf(L["Cannot finish auto looting, keeping %s slots free."], TSM.db.global.keepMailSpace) private.keepFreeSlots = false end private.mode = nil private.resetIndex = nil private.autoLootTotal = nil if not private.frame then return end private.frame:EnableButtons() --Tell user how much money has been collected if they don't have it turned off in TradeSkillMaster_Mailing options if private.moneyCollected and private.moneyCollected > 0 and TSM.db.global.displayMoneyCollected then TSM:Printf(L["%s total gold collected!"], TSMAPI:FormatTextMoney(private.moneyCollected)) private.moneyCollected = 0 end end function private:GetBagSlots() local genericSpace, uniqueSpace, partSlots = {}, {}, {} for bag = 0, NUM_BAG_SLOTS do if (GetItemFamily(GetBagName(bag)) or 0) > 0 then uniqueSpace[bag] = GetContainerNumFreeSlots(bag) or 0 else genericSpace[bag] = GetContainerNumFreeSlots(bag) or 0 end for slot = 1, GetContainerNumSlots(bag) do local iLink = GetContainerItemLink(bag, slot) if iLink then if not partSlots[bag] then partSlots[bag] = {} end table.insert(partSlots[bag], slot) end end end return genericSpace, uniqueSpace, partSlots end function Inbox:UI_ERROR_MESSAGE(event, msg) if msg == ERR_MAIL_DATABASE_ERROR then -- recover from internal mail error TSMAPI:CreateTimeDelay("mailWaitDelay", 1, private.AutoLoot) elseif msg == ERR_INV_FULL or msg == ERR_ITEM_MAX_COUNT then -- Try the next index in case we can still loot more such as in the case of glyphs private.lootIndex = private.lootIndex + 1 -- If we've exhausted all slots, but we still have <50 and more mail pending, wait until new data comes and keep looting it local current, total = GetInboxNumItems() if private.lootIndex > current then if private.lootIndex > total and total <= 50 then private:StopAutoLooting(true) end return end TSMAPI:CreateTimeDelay("mailWaitDelay", math.max(5/GetFramerate(), 0.3), private.AutoLoot) end end function Inbox:MAIL_CLOSED() private.resetIndex = nil private.allowTimerStart = true private.waitingForData = nil private:StopAutoLooting() TSMAPI:CancelFrame("inboxLootTextDelay") TSMAPI:CancelFrame("mailSkipDelay") Inbox:UnregisterEvent("UI_ERROR_MESSAGE") --sometimes shows error messages even when closed, so unregister that event. end