function handle()

in site/api/preferences.lua [63:412]


function handle(r)
    cross.contentType(r, "application/json")
    local DEBUG = config.debug or false
    local START = DEBUG and r:clock() or nil
    local get = r:parseargs()
    
    
    local login = {
        loggedIn = false
    }
    
    local prefs = nil 
    
    
    local account = user.get(r)
    
    
    if get.logout and account then
        user.logout(r, account)
        r:puts[[{"logout": true}]]
        return cross.OK
    end
    
    
    if get.associate and account and get.associate:match("^%S+@%S+$") then
        local fp, lp = get.associate:match("([^@]+)@([^@]+)")
        if config.no_association then
            for k, v in pairs(config.no_association) do
                if r.strcmp_match(lp:lower(), v) or v == "*" then
                    r:puts(JSON.encode{error="You cannot associate email addresses from this domain"})
                    return cross.OK
                end
            end
        end

        if get.associate == account.credentials.email then
            r:puts(JSON.encode{error="The primary mail address cannot be added as an alternate"})
            return cross.OK
        end


        account.credentials.altemail = account.credentials.altemail or {}
        filtertable(account.credentials.altemail)
        local duplicateRequest = false
        for k, v in pairs(account.credentials.altemail) do
            if v.email == get.associate then 
                if v.verified then 
                    r:puts(JSON.encode{error="That email is already defined as an alternate"})
                    
                    return cross.OK
                else 
                    v.hash = hash 
                    
                    
                    duplicateRequest = true
                end
            end
        end

        local hash = r:md5(math.random(1,999999) .. os.time() .. account.cid)
        local scheme = "https"
        if r.port == 80 then
            scheme = "http"
        end
        local domain = ("%s://%s:%u/"):format(scheme, r.hostname, r.port)
        if r.headers_in['Referer'] and r.headers_in['Referer']:match("merge%.html") then
            domain = r.headers_in['Referer']:gsub("/merge%.html", "/")
        end
        local vURL = ("%sapi/preferences.lua?verify=true&hash=%s"):format(domain, hash)
        
        local mldom = r.headers_in['Referer'] and r.headers_in['Referer']:match("https?://([^/:]+)") or r.hostname
        if not mldom then mldom = r.hostname end
        
        
        local source = smtp.message{
                headers = {
                    subject = "Confirm email address association in Pony Mail",
                    to = get.associate,
                    from = ("\"Pony Mail\"<no-reply@%s>"):format(mldom)
                    },
                body = ([[
You (or someone else) has requested to associate the email address '%s' with the account '%s' in Pony Mail.
If you wish to complete this association, please visit
%s
whilst logged in to Pony Mail.
Note: if you have repeated the association request, only the last URL will work.
 ...Or if you didn't request this, just ignore this email.

With regards,
Pony Mail - Email for Ponies and People.
]]):format(get.associate, account.credentials.email, vURL)
            }
        
        -- send email!
        local rv, er = smtp.send{
            from = ("\"Pony Mail\"<no-reply@%s>"):format(r.hostname),
            rcpt = get.associate,
            source = source,
            server = config.mailserver,
            port = config.mailport or nil -- if not specified, use the default
        }
         -- only update the account if the mail was sent OK
        if rv then
            if not duplicateRequest then
                table.insert(account.credentials.altemail, { email = get.associate, hash = hash, verified = false})
            end
            user.save(r, account, true)
        end
        r:puts(JSON.encode{requested = rv or er})
        return cross.OK
    end
    
    -- verify alt email?
    if get.verify and get.hash and account and account.credentials.altemail then
        filtertable(account.credentials.altemail)
        local verified = false
        for k, v in pairs(account.credentials.altemail) do
            if v.hash == get.hash then
                account.credentials.altemail[k].verified = true
                account.credentials.altemail[k].hash = nil
                verified = true
                -- fix all the matches
            end
        end
        user.save(r, account, true)
        -- response goes back to the browser direct
        cross.contentType(r, "text/plain")
        if verified then
            r:puts("Email address verified! Thanks for shopping at Pony Mail!\n")
        else
            r:puts("Either you supplied an invalid hash or something else went wrong.\n")
        end
        return cross.OK
    end
    
    -- remove alt email?
    if get.removealt and account and account.credentials.altemail then
        filtertable(account.credentials.altemail)
        for k, v in pairs(account.credentials.altemail) do
            if v.email == get.removealt then
                table.remove(account.credentials.altemail, k)
                break
            end
        end
        user.save(r, account, true)
        r:puts(JSON.encode{removed = true})
        return cross.OK
    end

    -- Or are you saving your preferences?
    if get.save and account then
        prefs = {}
        for k, v in pairs(get) do
            if k ~= 'save' then
                prefs[k] = v
            end
        end
        account.preferences = prefs
        user.save(r, account)
        r:puts[[{"saved": true}]]
        return cross.OK
    end
       
    -- Adding a favorite list
    if get.addfav and account then
        local add = get.addfav
        local favs = account.favorites or {}
        local found = false
        -- ensure it's not already there....
        for k, v in pairs(favs) do
            if v == add then
                found = true
                break
            end
        end
        
        if not found then
            table.insert(favs, add)
        end
        
        account.favorites = favs
        user.favs(r, account)
        r:puts[[{"saved": true}]]
        return cross.OK
    end
    
    
    if get.remfav and account then
        local rem = get.remfav
        local favs = account.favorites or {}
        
        for k, v in pairs(favs) do
            if v == rem then
                table.remove(favs, k)
                break
            end
        end
        
        account.favorites = favs
        user.favs(r, account)
        r:puts[[{"saved": true}]]
        return cross.OK
    end

    
    for _, v in pairs({'associate', 'verify', 'removealt', 'save', 'addfav', 'remfav'}) do
        if get[v] then
            if not account then
                r:puts(JSON.encode{error="Not logged in"})
            else
                r:puts(JSON.encode{error="Missing or invalid parameter(s)"})
            end
            return cross.OK
        end
    end

    
    local NOWISH = math.floor(os.time() / 600)
    local PM_LISTS_KEY = "pm_lists_counts_" .. r.hostname .. "-" .. NOWISH
    local cache = r:ivm_get(PM_LISTS_KEY)
    local listcounts = {} 
    if cache then
        listcounts = JSON.decode(cache)
    else
        

        local alldocs = elastic.raw{
            size = 0, 
            aggs = {
                listnames = {
                    terms = {
                        field = "list_raw",
                        size = utils.MAX_LIST_COUNT
                    },
                    aggs = {
                        
                        privacy = {
                            terms = {
                                field = "private"
                            },
                            aggs = {
                                
                                recent = {
                                    range = {
                                        field = "date",
                                        ranges = { {from = "now-90d"} }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        
        for _, entry in pairs (alldocs.aggregations.listnames.buckets) do
            local listname = entry.key:lower()
            listcounts[listname] = {}
            
            for _, privacy in pairs(entry.privacy.buckets) do
                listcounts[listname][privacy.key_as_string] = privacy.recent.buckets[1].doc_count
            end
        end
        
        r:ivm_set(PM_LISTS_KEY, JSON.encode(listcounts))
    end

    
    local lists = {}
    for listname, entry in pairs(listcounts) do
        local _, list, domain = aaa.parseLid(listname)
        
        
        if list and domain and #list > 0 and #domain > 0 then
            
            for privacy, recent_count in pairs(entry) do
                local isPublic = privacy == 'false'
                
                if isPublic or aaa.canAccessList(r, listname, account)  then
                    
                    lists[domain] = lists[domain] or {}
                    
                    if lists[domain][list] then
                        lists[domain][list] = lists[domain][list] + recent_count
                    else
                        lists[domain][list] = recent_count 
                    end
                end
            end
        end
    end
    
        
    if config.listsDisplay then
        for k, v in pairs(lists) do
            if not k:match(config.listsDisplay) then
                lists[k] = nil
            end
        end
    end

    
    
    local notifications = 0
    if account then
        local _, notifs = pcall(function() return elastic.find("seen:0 AND recipient:" .. r:sha1(account.cid), 10, "notifications") end)
        if notifs and #notifs > 0 then
            notifications = #notifs
        end
    end
     
    account = account or {}
    local stat, descs = pcall(function() return elastic.find("*", 9999, "mailinglists", "name") end)
    if not stat or not descs then
        descs = {} 
    end
    
    for k, v in pairs(descs) do
        local _, l, d = aaa.parseLid(v.list:lower())
        if l and d then
            descs[k].lid = ("%s@%s"):format(l, d)
        else
            descs[k].lid = v.list
        end
    end
    
    local alts = {}
    if account and account.credentials and type(account.credentials.altemail) == "table" then
        filtertable(account.credentials.altemail)
        for k, v in pairs(account.credentials.altemail) do
            if v.verified then
                table.insert(alts, v.email)
            end
        end
    end
    r:puts(JSON.encode{
        lists = lists,
        descriptions = descs,
        preferences = account.preferences,
        login = {
            favorites = account.favorites,
            credentials = account.credentials,
            notifications = notifications,
            alternates = alts
        },
        took = DEBUG and (r:clock() - START) or nil
    })
    
    return cross.OK
end