Adding luakit scripts, creating a mutt folder instead of just .muttrc, and adding urlview config
parent
a44fcd5269
commit
e43c8e0f36
@ -0,0 +1,216 @@
|
||||
----------------------------------------------------------------
|
||||
-- Multi-Session save/restore Plugin --
|
||||
----------------------------------------------------------------
|
||||
|
||||
local ipairs = ipairs
|
||||
local tostring = tostring
|
||||
local lfs = lfs
|
||||
local os = os
|
||||
local io = io
|
||||
local table = table
|
||||
local string = string
|
||||
local unpack = unpack
|
||||
local lousy = require "lousy"
|
||||
local util = lousy.util
|
||||
local luakit = luakit
|
||||
local window = window
|
||||
local add_binds, add_cmds = add_binds, add_cmds
|
||||
local new_mode, menu_binds = new_mode, menu_binds
|
||||
local cmd = lousy.bind.cmd
|
||||
local buf = lousy.bind.buf
|
||||
|
||||
module("plugins.multisession")
|
||||
|
||||
local sessions_dir = luakit.data_dir .. "/sessions"
|
||||
|
||||
local rm = function (file)
|
||||
luakit.spawn(string.format("rm %q", file))
|
||||
end
|
||||
|
||||
local session_save = function (w, name)
|
||||
if not name then return end
|
||||
local fpath = sessions_dir .. "/" .. (name or "")
|
||||
-- Save all given windows uris to file.
|
||||
local lines = {}
|
||||
-- Save tabs from all the given window, keep the window-index to keep
|
||||
-- comptability with default sessions format
|
||||
local current = w.tabs:current()
|
||||
for ti, tab in ipairs(w.tabs.children) do
|
||||
table.insert(lines, string.format("%d\t%d\t%s\t%s", 1, ti,
|
||||
tostring(current == ti), tab.uri))
|
||||
end
|
||||
-- Only save a non-empty session
|
||||
if #lines > 0 then
|
||||
local fh = io.open(fpath, "w")
|
||||
fh:write(table.concat(lines, "\n"))
|
||||
io.close(fh)
|
||||
else
|
||||
rm(session.file)
|
||||
end
|
||||
end
|
||||
|
||||
local session_load = function (name)
|
||||
local fpath = sessions_dir .. "/" .. (name or "")
|
||||
if not name or not os.exists(fpath) then return end
|
||||
local ret = {}
|
||||
|
||||
-- Read file
|
||||
local lines = {}
|
||||
local fh = io.open(fpath, "r")
|
||||
for line in fh:lines() do table.insert(lines, line) end
|
||||
io.close(fh)
|
||||
|
||||
-- Parse session file, again, ignore the window-index, keeping for
|
||||
-- compatibility
|
||||
for _, line in ipairs(lines) do
|
||||
local wi, ti, current, uri = unpack(util.string.split(line, "\t"))
|
||||
current = (current == "true")
|
||||
table.insert(ret, {uri = uri, current = current})
|
||||
end
|
||||
|
||||
return (#ret > 0 and ret) or nil
|
||||
end
|
||||
|
||||
-- Create a new window and open all tabs in the session in it
|
||||
local session_restore = function (name)
|
||||
win = session_load(name)
|
||||
if not win or #win == 0 then return end
|
||||
|
||||
-- Spawn windows
|
||||
local w
|
||||
for _, item in ipairs(win) do
|
||||
if not w then
|
||||
w = window.new({item.uri})
|
||||
else
|
||||
w:new_tab(item.uri, item.current)
|
||||
end
|
||||
end
|
||||
return w
|
||||
end
|
||||
|
||||
-- Opens all tabs in named session in current window
|
||||
local session_append = function (w, name)
|
||||
ses = session_load(name)
|
||||
if not ses or #ses == 0 then return false end
|
||||
for _, item in ipairs(ses) do
|
||||
w:new_tab(item.uri, item.current)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local session_del = function (name)
|
||||
if not name then return end
|
||||
local fpath = sessions_dir .. "/" .. (name or "")
|
||||
if not os.exists(fpath) then return false end
|
||||
rm(fpath)
|
||||
return true
|
||||
end
|
||||
|
||||
local load = function ()
|
||||
local curdir = lfs.currentdir()
|
||||
if not lfs.chdir(sessions_dir) then
|
||||
lfs.mkdir(sessions_dir)
|
||||
else
|
||||
lfs.chdir(curdir)
|
||||
end
|
||||
end
|
||||
|
||||
add_cmds({
|
||||
cmd("session", "view list of sessions", function (w) w:set_mode("sessionmenu") end),
|
||||
cmd({"session-write", "sw"}, "save a session to file",
|
||||
function (w, a)
|
||||
local name = util.string.strip(a) or "default"
|
||||
session_save(w, name)
|
||||
w:notify("Saved " .. tostring(w.tabs:count()) .. " tabs to session " .. name .. ".")
|
||||
end),
|
||||
cmd({"session-delete", "sd"}, "delete a saved session",
|
||||
function(w, a)
|
||||
local name = util.string.strip(a)
|
||||
if session_del(name) then
|
||||
w:notify("Deleted session " .. name .. ".")
|
||||
else
|
||||
w:error("No saved session named " .. name .."!")
|
||||
end
|
||||
end),
|
||||
cmd({"session-restore", "sr"}, "load a saved session in a new window",
|
||||
function(w, a)
|
||||
local name = util.string.strip(a) or "default"
|
||||
if not session_restore(name) then
|
||||
w:error("Unable to restore session " .. name .. "!")
|
||||
end
|
||||
end),
|
||||
cmd({"session-open", "so"}, "open a saved session in new tabs in current window",
|
||||
function(w, a)
|
||||
local name = util.string.strip(a) or "default"
|
||||
if not session_append(w, name) then
|
||||
w:error("Unable to open session " .. name .. "!")
|
||||
else
|
||||
w:notify("Appended session " .. name .. " to tabs.")
|
||||
end
|
||||
end),
|
||||
})
|
||||
|
||||
add_binds("normal", {
|
||||
buf("^sm$", "open list of saved sessions", function(w) w:set_mode("sessionmenu") end),
|
||||
})
|
||||
|
||||
|
||||
|
||||
new_mode("sessionmenu", {
|
||||
enter = function (w)
|
||||
local rows = {{"Saved Sessions (# of tabs)", title = true}}
|
||||
|
||||
for filename in lfs.dir(sessions_dir) do
|
||||
if not string.match(filename, "^%.-$") then
|
||||
local fh = io.open(sessions_dir .. "/" .. filename)
|
||||
local tabcnt = 0
|
||||
for _ in fh:lines() do tabcnt = tabcnt + 1 end
|
||||
io.close(fh)
|
||||
table.insert(rows, {string.format(" %s (%d)", filename, tabcnt), name = filename})
|
||||
end
|
||||
end
|
||||
if #rows == 1 then
|
||||
table.insert(rows, {"No saved sessions!"})
|
||||
end
|
||||
w.menu:build(rows)
|
||||
w:notify("Use j/k to move, d to delete a session, t to append session to current window, Enter to open session (in new window)", false)
|
||||
end,
|
||||
|
||||
leave = function (w)
|
||||
w.menu:hide()
|
||||
end,
|
||||
})
|
||||
|
||||
local key = lousy.bind.key
|
||||
add_binds("sessionmenu", lousy.util.table.join({
|
||||
key({}, "Return", function (w)
|
||||
local row = w.menu:get()
|
||||
if row and row.name then
|
||||
w:set_mode()
|
||||
session_restore(row.name)
|
||||
end
|
||||
end),
|
||||
|
||||
key({}, "t", function (w)
|
||||
local row = w.menu:get()
|
||||
if row and row.name then
|
||||
w:set_mode()
|
||||
session_append(w, row.name)
|
||||
end
|
||||
end),
|
||||
|
||||
key({}, "d", function (w)
|
||||
local row = w.menu:get()
|
||||
if row and row.name then
|
||||
w.menu:del()
|
||||
session_del(row.name)
|
||||
end
|
||||
end),
|
||||
|
||||
-- Exit menu
|
||||
key({}, "q", function (w) w:set_mode() end),
|
||||
|
||||
}, menu_binds))
|
||||
|
||||
load()
|
||||
-- vim: et:sw=4:ts=8:sts=4:tw=80
|
@ -0,0 +1,66 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- No-Scipt Status Widget --
|
||||
-- Adds a simple, skinnable, widget to the status bar to indicate the --
|
||||
-- current status of scripts and plugins --
|
||||
-- --
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local string = string
|
||||
local window = window
|
||||
local webview = webview
|
||||
local widget = widget
|
||||
local theme = theme
|
||||
local luakit = luakit
|
||||
local domain_props = domain_props
|
||||
local lousy = require("lousy")
|
||||
local history = require("history")
|
||||
|
||||
module("plugins.nscript_widget")
|
||||
|
||||
-- Strings widget uses
|
||||
local script_str = { enabled = "s", disabled = "!s" }
|
||||
local plugin_str = { enabled = "p", disabled = "!p" }
|
||||
|
||||
|
||||
-- Load themes, if undefined fallback
|
||||
theme.nsw_enabled = theme.nsw_enabled or "#0f0"
|
||||
theme.nsw_disabled = theme.nsw_disabled or "#f00"
|
||||
|
||||
-- Create the indictor widget on window creation
|
||||
window.init_funcs.build_ns_indicator = function(w)
|
||||
local i = w.sbar.r
|
||||
i.noscr = widget{type="label"}
|
||||
i.layout:pack(w.sbar.r.noscr)
|
||||
i.layout:reorder(w.sbar.r.noscr, 2)
|
||||
i.noscr.font = theme.buf_sbar_font
|
||||
w:update_noscr()
|
||||
-- Update indicator on tab change
|
||||
w.tabs:add_signal("switch-page", function (_,view)
|
||||
luakit.idle_add(function() w:update_noscr(w) return false end)
|
||||
end)
|
||||
end
|
||||
|
||||
-- Update indicator on page navigation
|
||||
webview.init_funcs.noscr_update = function(view, w)
|
||||
view:add_signal("load-status", function (v, status)
|
||||
if status == "committed" or status == "failed" or status == "finished" then
|
||||
w:update_noscr()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Method wrapper
|
||||
window.methods.update_noscr = function(w)
|
||||
if not w.view then return end
|
||||
local scripts = w.view.enable_scripts
|
||||
local plugins = w.view.enable_plugins
|
||||
local noscr = w.sbar.r.noscr
|
||||
local tmpl = '<span foreground="%s">%s</span> <span foreground="%s">%s</span>'
|
||||
noscr.text = string.format(tmpl,
|
||||
( scripts and theme.nsw_enabled ) or theme.nsw_disabled,
|
||||
( scripts and script_str.enabled ) or script_str.disabled,
|
||||
( plugins and theme.nsw_enabled ) or theme.nsw_disabled,
|
||||
( plugins and plugin_str.enabled ) or plugin_str.disabled)
|
||||
noscr:show()
|
||||
end
|
@ -0,0 +1,969 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- Advanced URI-based content filter v0.1.1a --
|
||||
-- Combines functionality of AdBlock via pattern-match based blocking, --
|
||||
-- domain/sub-domain matching white and black listing, --
|
||||
-- a RequestPolicy-like rule system to default-deny 3rd-party requests --
|
||||
-- and rough per-domain file-type filtering based on URI patterns --
|
||||
-- --
|
||||
-- Disclaimer: while this is intended to increase browser security and --
|
||||
-- help protect privacy, there is no guarantee. Rely on it at your own risk! --
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local info = info
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local assert = assert
|
||||
local unpack = unpack
|
||||
local type = type
|
||||
local io = io
|
||||
local os = os
|
||||
local string = string
|
||||
local table = table
|
||||
local tostring = tostring
|
||||
local tonumber = tonumber
|
||||
local webview = webview
|
||||
local window = window
|
||||
local lousy = require("lousy")
|
||||
local theme = theme
|
||||
local widget = widget
|
||||
local util = lousy.util
|
||||
local chrome = require("chrome")
|
||||
local capi = { luakit = luakit , sqlite3 = sqlite3 }
|
||||
local sql_escape = lousy.util.sql_escape
|
||||
local add_binds, add_cmds = add_binds, add_cmds
|
||||
local new_mode, menu_binds = new_mode, menu_binds
|
||||
local lfs = require("lfs")
|
||||
local setmetatable = setmetatable
|
||||
|
||||
-- Public Suffix Lib
|
||||
local tld = require("tld")
|
||||
local getdomain = tld.getdomain
|
||||
|
||||
-- Calls modifed adblock
|
||||
--local adblock = require("plugins.adblock")
|
||||
|
||||
module("plugins.policy")
|
||||
|
||||
pdebug = function (...) io.stdout:write(string.format(...) .. "\n") end
|
||||
|
||||
-- Settings Flags =============================================================
|
||||
filtering = {
|
||||
-- Flag to accept all requests (disabled all blocking)
|
||||
acceptall = false,
|
||||
-- Flag to enable/disable AdBlock / Pattern-Based Blocking
|
||||
adblock = true,
|
||||
-- Flag to enable/disable additional scrutiny of 3rd-party requests
|
||||
requestpolicy = true,
|
||||
-- Flag to enable/disable file-type blocking policy
|
||||
typepolicy = true,
|
||||
-- Flag for whether a subdomain is treated as a 3rd party relative to other subdomains or master domain
|
||||
strictsubdomain = false,
|
||||
-- Flas for whether to show status bar widget
|
||||
widget = true
|
||||
}
|
||||
|
||||
local policy_dir = capi.luakit.data_dir
|
||||
|
||||
-- Below is the actual internals of the plugin, here be dragons ---------------
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
-- Cache to reduce sql calls
|
||||
local cache = {}
|
||||
setmetatable(cache, { __mode = "k" })
|
||||
|
||||
-- A table to store data for navigation and resource requests
|
||||
-- it has per-view instances, indexed via navto[v].fields
|
||||
local navto = {}
|
||||
setmetatable(navto, { __mode = "k" })
|
||||
|
||||
-- Exception listing
|
||||
local exlist = { white = {}, third = {white = {} } }
|
||||
|
||||
-- Makes the following more clear... eg: return codes and internal constants
|
||||
-- allowing is zero so that reasons for denial can be communicated
|
||||
local ALLOW = 0
|
||||
local DENIED = { BLACKLIST = 1, ADBLOCK = 2, NO_WHITELIST = 3, BLACKLISTED_TP = 4 , BLOCKED_TYPE = 5 }
|
||||
local ANY_PARTY, THIRD_PARTY = 1, 2
|
||||
local reasonstring = {"Blacklisted", "ABP", "CDR", "Blacklisted-CDR", "F-TYPE", "Other"}
|
||||
|
||||
-- sqlite command stings
|
||||
local create_tables = [[
|
||||
PRAGMA synchronous = OFF;
|
||||
PRAGMA secure_delete = 1;
|
||||
CREATE TABLE IF NOT EXISTS whitelist (
|
||||
id INTEGER PRIMARY KEY,
|
||||
domain TEXT UNIQUE);
|
||||
CREATE TABLE IF NOT EXISTS blacklist (
|
||||
id INTEGER PRIMARY KEY,
|
||||
domain TEXT UNIQUE);
|
||||
CREATE TABLE IF NOT EXISTS tp_whitelist (
|
||||
id INTEGER PRIMARY KEY,
|
||||
domain TEXT,
|
||||
rdomain TEXT);
|
||||
CREATE TABLE IF NOT EXISTS tp_blacklist (
|
||||
id INTEGER PRIMARY KEY,
|
||||
domain TEXT,
|
||||
rdomain TEXT);
|
||||
]]
|
||||
|
||||
local sql_format = {
|
||||
match_list = "SELECT * FROM %slist WHERE domain == %s;",
|
||||
add_list = "INSERT INTO %slist VALUES (NULL, %s);",
|
||||
remove_list = "DELETE FROM %slist WHERE domain == %s;",
|
||||
match_tp_list = "SELECT * FROM tp_%slist WHERE domain == %s and rdomain == %s;",
|
||||
add_tp_list = "INSERT INTO tp_%slist VALUES (NULL, %s, %s);",
|
||||
remove_tp_list_exact = "DELETE FROM tp_%slist WHERE domain == %s and rdomain == %s;",
|
||||
|
||||
remove_tp_list_domain = "DELETE FROM tp_%slist WHERE domain == %s;",
|
||||
remove_tp_list_rdomain = "DELETE FROM tp_%slist WHERE rdomain == %s;",
|
||||
}
|
||||
|
||||
-- Open or create & initiaze dbi
|
||||
initalize_rpdb = function()
|
||||
if rpdb then return end
|
||||
rpdb = capi.sqlite3{ filename = policy_dir .. "/policy.db" }
|
||||
rpdb:exec(create_tables)
|
||||
end
|
||||
|
||||
-- Helper functions that perform various utility functions ========================
|
||||
|
||||
-- Attempt to parse a uri for the extension of the requested file
|
||||
-- return file extension in lower case or "NONE" if no extension
|
||||
local getextension = function (uri)
|
||||
if uri then
|
||||
local puri = lousy.uri.parse(uri)
|
||||
local ext = string.match(puri and puri.path or "", "%.([a-zA-Z0-9]-)$")
|
||||
return ext and string.lower(ext) or "NONE"
|
||||
end
|
||||
return "NONE"
|
||||
end
|
||||
|
||||
-- Check if query is domain or a subdomain of host
|
||||
local subdomainmatch = function(host, query)
|
||||
if host == query then
|
||||
return true
|
||||
else
|
||||
local abits = util.string.split(string.reverse(host or ""), "%.")
|
||||
local bbits = util.string.split(string.reverse(query or ""), "%.")
|
||||
-- If host is an IP abort, eg: 10.8.4.1 is not a subdomain of 8.4.1
|
||||
if host and string.match(host, "^%d%.%d%.%d%.%d$") then return false end
|
||||
-- TODO ipv6 match
|
||||
for i,s in ipairs(abits) do
|
||||
if s ~= bbits[i] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
-- Checks domains for a match
|
||||
local domainmatch = function (a, b)
|
||||
-- If main uri (a) is nil, then it is always "first party"
|
||||
-- If a == b then they are the same domain
|
||||
-- Otherwise do a match score and make a fuzzy match
|
||||
if not a or a == b then
|
||||
return true
|
||||
elseif not filtering.strictsubdomain then
|
||||
local abits = util.string.split(string.reverse(a) or "", "%.")
|
||||
local bbits = util.string.split(string.reverse(b) or "", "%.")
|
||||
local matching = 0
|
||||
-- If an IP, don't do partial matches, TODO ipv6 match
|
||||
if string.match(a, "^%d%.%d%.%d%.%d$") then return false end
|
||||
-- Count matching bits
|
||||
for i,s in ipairs(abits) do
|
||||
if s == bbits[i] then
|
||||
matching = matching + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
-- Check the effective tlds of a and b and use that + 1 as the minimum matching requirement
|
||||
local ab = util.string.split(getdomain(a), "%.")
|
||||
local bb = util.string.split(getdomain(b), "%.")
|
||||
local needed_match = ( (#ab > #bb) and #ab) or #bb
|
||||
if matching >= needed_match then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns whether or not rhost is whitelisted
|
||||
local islisted = function (host, rhost, typ, party)
|
||||
if party == THIRD_PARTY then
|
||||
local host_bits = util.table.reverse(util.string.split(host or "", "%.") or {})
|
||||
-- Get base domain, we do not want to match vs. just public suffixes
|
||||
local n = 1
|
||||
local phost = getdomain(host)
|
||||
if not string.match(phost, "^[0-9%.]$") then
|
||||
local pbits = util.string.split(phost, "%.")
|
||||
n = #pbits + 1
|
||||
else
|
||||
n = #host_bits
|
||||
end
|
||||
local list, tlist
|
||||
-- Make list to match rhost against, use cache if valid
|
||||
if cache[host] and cache[host][typ] then
|
||||
list = cache[host][typ]
|
||||
if typ == "white" then
|
||||
tlist = exlist.third.white["all"]
|
||||
repeat
|
||||
tlist = util.table.join(tlist, exlist.third.white[phost] or {})
|
||||
phost = (host_bits[n] or "").. "." .. phost
|
||||
n = n + 1
|
||||
until n > #host_bits + 1
|
||||
end
|
||||
else
|
||||
list = rpdb:exec(string.format("SELECT * FROM tp_%slist WHERE domain = %s;", typ, sql_escape("all")))
|
||||
tlist = exlist.third.white["all"]
|
||||
repeat
|
||||
local rows = rpdb:exec(string.format("SELECT * FROM tp_%slist WHERE domain = %s;", typ, sql_escape(phost)))
|
||||
list = util.table.join(list, rows or {})
|
||||
if typ == "white" then
|
||||
tlist = util.table.join(tlist, exlist.third.white[phost] or {})
|
||||
end
|
||||
phost = (host_bits[n] or "").. "." .. phost
|
||||
n = n + 1
|
||||
until n > #host_bits + 1
|
||||
-- Save list in cache
|
||||
if not cache[host] then cache[host] = {} end
|
||||
cache[host][typ] = list
|
||||
end
|
||||
-- Match vs lists
|
||||
for _,v in pairs(list) do
|
||||
if subdomainmatch(v.rdomain, rhost) or v.rdomain == "all" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
-- Only check exceptions if checking a whitelist
|
||||
if typ == "white" then
|
||||
for k,v in pairs(tlist) do
|
||||
if subdomainmatch(v, rhost) or v == "all" then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
else
|
||||
local list
|
||||
if cache[typ] then
|
||||
list = cache[typ]
|
||||
else
|
||||
list = rpdb:exec(string.format("SELECT * FROM %slist;", typ))
|
||||
cache[typ] = list
|
||||
end
|
||||
|
||||
for _,v in pairs(list) do
|
||||
if subdomainmatch(v.domain, rhost) then
|
||||
return true;
|
||||
end
|
||||
end
|
||||
-- Only check exceptions if checking a whitelist
|
||||
if typ == "white" then
|
||||
for k,v in pairs(exlist.white) do
|
||||
if subdomainmatch(k, rhost) then
|
||||
return true;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- No match was found
|
||||
return false
|
||||
end
|
||||
|
||||
-- Check Pattern list for matches to rules (aka AdBlocking)
|
||||
local patternMatch = function (req)
|
||||
-- This checks that the AdBlock Module is loaded, and if so it calls the matching function
|
||||
-- I originally intended to re-implement this as part of this plugin, but I decided that
|
||||
-- it was better to just use a minimally modified version of the upstream AdBlock plugin
|
||||
if filtering.adblock and adblock and adblock.match then
|
||||
return not adblock.match(req, "none")
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Main logic checking if a request should be allowed or denied
|
||||
local checkpolicy = function (host, requested, nav, firstnav)
|
||||
-- A request for a nil uri is denied (should never happen)
|
||||
if not requested then
|
||||
return DENIED.BLACKLIST
|
||||
end
|
||||
-- Should always accept these
|
||||
if string.match(requested, "about:blank") or filtering.acceptall then
|
||||
return ACCEPT
|
||||
end
|
||||
-- Get host from requested uri and file-type extension
|
||||
local rpuri = lousy.uri.parse(requested)
|
||||
local req = { host = string.lower(rpuri and rpuri.host or ""), ftype = getextension(requested) }
|
||||
-- webview.uri is nil for the first requests when loading a page (they are always first party)
|
||||
local puri = lousy.uri.parse(host or "")
|
||||
host = puri and puri.host or req.host
|
||||
|
||||
local wlisted = false
|
||||
-- Skip checks for data: uris - they would be covered by the policies of whatever they were embedded in
|
||||
if not string.match(requested, "^data:") then
|
||||
-- Blacklisting overrides whitelist
|
||||
if islisted(nil, req.host, "black", ANY_PARTY) then
|
||||
return DENIED.BLACKLIST
|
||||
end
|
||||
|
||||
-- Check if requested domain is whitelisted
|
||||
wlisted = islisted(nil, req.host, "white", ANY_PARTY)
|
||||
|
||||
-- Whitelisting overrides AdBlocking/Pattern Block
|
||||
if not wlisted and filtering.adblock then
|
||||
-- If AdBlock / Pattern matching is enabled, check if requested uri matches and should be blocked
|
||||
if patternMatch(requested) then
|
||||
return DENIED.ADBLOCK
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- If RequestPolicy is disabled or this is a first party request only type-blocking is checked
|
||||
-- If this is a a navigation request or the first request post-navigation, relax CDR, we likely clicked on a link
|
||||
-- data: uri's are not cross-domain, however we might want to check those with file filtering
|
||||
if nav or firstnav or not filtering.requestpolicy or domainmatch(host, req.host) or string.match(requested, "^data:")then
|
||||
-- TODO: file-type blocking
|
||||
return ACCEPT
|
||||
else
|
||||
-- Check if this domain is blacklised for ALL 3rd-party requests -OR-
|
||||
-- blacklisted for 3rd party requests for the main domain
|
||||
if islisted(host, req.host, "black", THIRD_PARTY) then
|
||||
return DENIED.BLACKLISTED_TP
|
||||
end
|
||||
|
||||
-- If requested host is whitelisted universally or for this host for this third party, set to accept
|
||||
local wlistedtp = islisted(host, req.host, "white", THIRD_PARTY)
|
||||
if not wlistedtp then
|
||||
return DENIED.NO_WHITELIST
|
||||
end
|
||||
-- TODO: file-type blocking that overrides whitelisted 3rd party requrests
|
||||
return ACCEPT
|
||||
end
|
||||
end
|
||||
|
||||
-- Make a table of request's hosts and keep a count of accepted and denied requests
|
||||
local concatRes = function (l, uri, r)
|
||||
if uri then
|
||||
local puri = lousy.uri.parse(uri)
|
||||
if puri and puri.host then
|
||||
-- If the host doesn't have a table yet, add it
|
||||
if not l[puri.host] then
|
||||
l[puri.host] = {accept = 0, deny = 0, reasons = {}}
|
||||
end
|
||||
-- Increment counter (s)
|
||||
if not r then
|
||||
l[puri.host].accept = 1 + l[puri.host].accept
|
||||
else
|
||||
l[puri.host].deny = 1 + l[puri.host].deny
|
||||
-- TODO get make this not so hacky ??
|
||||
l[puri.host].reasons[reasonstring[r]] = (l[puri.host].reasons[reasonstring[r]] or 0) + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Connect signals to all webview widgets on creation
|
||||
-- TODO check robustness of the firstnav system
|
||||
webview.init_funcs.policu_signals = function (view, w)
|
||||
view:add_signal("navigation-request",
|
||||
function (v, uri)
|
||||
-- Check if request should be accepted or denied
|
||||
local r = checkpolicy(v.uri, uri, true , false)
|
||||
|
||||
-- if navto[v] does not exist set to empty table
|
||||
navto[v] = navto[v] or {}
|
||||
|
||||
-- Only do the following if request was accepted (r = 0)
|
||||
if not r then
|
||||
-- Set temp navigation uri to the requested uri
|
||||
navto[v].uri = uri
|
||||
-- Make an empty request table if one does not exist
|
||||
navto[v].res = navto[v].res or {}
|
||||
-- Add request to the resource request table
|
||||
--concatRes(navto[v].res, uri, r) -- TODO I don't think this is needed?
|
||||
-- XXX "bug-fix" ensures uri bar gets updated on clicking intra-page links
|
||||
w:update_uri()
|
||||
elseif r == DENIED.BLACKLIST then
|
||||
w:error("Policy: Blacklisted domain '" .. uri .. "'")
|
||||
end
|
||||
-- Hack to get luakit:// pages to load
|
||||
local puri = lousy.uri.parse(uri or "")
|
||||
if puri and puri.scheme == "luakit" then
|
||||
else
|
||||
return not r
|
||||
end
|
||||
end)
|
||||
|
||||
view:add_signal("resource-request-starting",
|
||||
function (v, uri)
|
||||
-- Check if request should be accepted or denied
|
||||
local r = checkpolicy(navto[v].uri or v.uri, uri, false, (navto[v] or {}).first)
|
||||
|
||||
-- if w.navto[v] does not exist set to empty table
|
||||
navto[v] = navto[v] or {}
|
||||
-- Clear temp navigation uri
|
||||
navto[v].uri = nil
|
||||
-- Clear first flag
|
||||
navto[v].first = false
|
||||
-- Add the request to the request table
|
||||
concatRes(navto[v].res, uri, r)
|
||||
|
||||
-- Hack to get luakit;// pages to load
|
||||
local puri = lousy.uri.parse(uri or "")
|
||||
if puri and puri.scheme == "luakit" then
|
||||
else
|
||||
return not r
|
||||
end
|
||||
end)
|
||||
|
||||
view:add_signal("load-status",
|
||||
function (v, status)
|
||||
--pdebug(("policy: load-status signal uri = " .. (v.uri or "") .. "status = " .. status) or "policy: load-status ???")
|
||||
navto[v] = navto[v] or {}
|
||||
if status == "provisional" then
|
||||
-- Resets Resource requests
|
||||
navto[v].res = {}
|
||||
navto[v].first = true
|
||||
elseif status == "committed" then
|
||||
navto[v].first = false
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- TODO - All the chrome stuff...
|
||||
-- luakit://policy/help help page, lists commands and explains how to use plugin
|
||||
-- luakit://policy displys settings status and links to other pages
|
||||
-- luakit://policy/whitelist list of whitelisted domains (button to remove, search, and add new entries)
|
||||
-- luakit://policy/blacklist list of blacklisted domains (button to remove, search, and add new entries)
|
||||
-- luakit://policy/cdr/whitelist list of CDR whitelist entries (")
|
||||
-- luakit://policy/cdr/blacklist list of CDR blacklist entries (")
|
||||
-- luakit://policy/adblock redirects to luakit://adblock
|
||||
|
||||
load = function ()
|
||||
-- Load the db with the white/black lists
|
||||
initalize_rpdb()
|
||||
end
|
||||
|
||||
-- Functions called by user commands ==========================================
|
||||
local togglestrings = {
|
||||
acceptall = "unconditional accepting of all requests.",
|
||||
adblock = "pattern-based blocking (aka AdBlock).",
|
||||
requestpolicy = "cross-domain request policy blocking.",
|
||||
typepolicy = "cross-domain file-type blocking",
|
||||
strictsubdomain = "strict matching for subdomains.",
|
||||
widget = "visibility of status widget.",
|
||||
}
|
||||
|
||||
local rp_setting = function (field, value, w)
|
||||
-- Check that field is a valid settings field
|
||||
if togglestrings[field] then
|
||||
-- Check is toggling or setting value
|
||||
if value == "toggle" then
|
||||
filtering[field] = not filtering[field]
|
||||
else
|
||||
filtering[field] = value
|
||||
end
|
||||
-- User feedback on what setting was changed and what it was changed to
|
||||
w:notify("Policy: " .. (value and "en" or "dis") .. "abled " .. togglestrings[field])
|
||||
end
|
||||
-- return validity of the setting
|
||||
return togglestrings[field] and true
|
||||
end
|
||||
|
||||
-- Clears Excption lists and returns the number of items they contained
|
||||
local clear_exlist = function ()
|
||||
local listlen = #exlist.white
|
||||
for _,v in pairs(exlist.third.white) do
|
||||
for _,_ in pairs(v) do
|
||||
listlen = listlen + 1
|
||||
end
|
||||
end
|
||||
exlist.white = {}
|
||||
exlist.third.white = {}
|
||||
return listlen or 0
|
||||
end
|
||||
|
||||
-- Returns true if entery exists
|
||||
local checkList = function (typ, hosts)
|
||||
local host = hosts[1]
|
||||
local rhost = hosts[2]
|
||||
if rhost then
|
||||
if typ == "ex" then
|
||||
return exlist.third.white[host] and util.table.hasitem(exlist.third.white[host], rhost) and true
|
||||
elseif typ == "white" or typ == "black" then
|
||||
local row = rpdb:exec(string.format(sql_format.match_tp_list, typ, sql_escape(host), sql_escape(rhost)))
|
||||
return row and row[1] and true
|
||||
end
|
||||
else
|
||||
if typ == "ex" then
|
||||
return util.table.hasitem(exlist.white, host) and true
|
||||
elseif typ == "white" or typ == "black" then
|
||||
local row = rpdb:exec(string.format(sql_format.match_list, typ, sql_escape(host)))
|
||||
return row and row[1] and true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Return Strings, makes localization easier
|
||||
local retStr = {
|
||||
sucess = {
|
||||
add = {
|
||||
one = {
|
||||
ex = "Exception added for %s",
|
||||
white = "Added %s to whitelist",
|
||||
black = "Added %s to blacklist"},
|
||||
mul = {
|
||||
ex = "Exception added for requests from %s to %s",
|
||||
white = "Whitelisted requests from %s made to %s",
|
||||
black = "Blacklisted requests from %s made to %s"},
|
||||
},
|
||||
del = {
|
||||
one = {
|
||||
ex = "Removed exception for %s",
|
||||
white = "Removed %s from whitelist",
|
||||
black = "Removed %s from blacklist"},
|
||||
mul = {
|
||||
ex = "Exception removed for requests from %s to %s",
|
||||
white = "Removed whitelisting of requests from %s to %s",
|
||||
black = "Removed blacklisting of requests from %s to %s"},
|
||||
},
|
||||
},
|
||||
failure = {
|
||||
add = {
|
||||
one = {
|
||||
ex = "Exception had already been granted to %s!",
|
||||
white = "%s was already whitelisted!",
|
||||
black = "%s was already blacklisted!"},
|
||||
mul = {
|
||||
ex = "Exception had already been granted to requests from %s to %s!",
|
||||
white = "Requests from %s to %s were already whitelisted!",
|
||||
black = "Requests from %s to %s were already blacklisted!"},
|
||||
},
|
||||
del = {
|
||||
one = {
|
||||
ex = "Exception had not been granted to %s!",
|
||||
white = "%s was not whitelisted!",
|
||||
black = "%s was not blacklsited!"},
|
||||
mul = {
|
||||
ex = "Requests from %s to %s had not been granted an exception!",
|
||||
white = "Requests from %s to %s were not whitelisted!",
|
||||
black = "Requests from %s to %s were not blacklisted!"},
|
||||
},
|
||||
}} -- end retStr
|
||||
|
||||
local modList = function (cmd, typ, hosts, w)
|
||||
local host = hosts[1]
|
||||
local rhost = hosts[2]
|
||||
local listed = checkList(typ, hosts)
|
||||
local num = (rhost and "mul") or "one"
|
||||
local suc = "failure"
|
||||
if cmd == "add" then
|
||||
if not listed then
|
||||
if rhost then
|
||||
if typ == "white" or typ == "black" then
|
||||
rpdb:exec(string.format(sql_format.add_tp_list,
|
||||
typ, sql_escape(host), sql_escape(rhost)))
|
||||
else
|
||||
if not exlist.third.white[host] then
|
||||
exlist.third.white[host] = {}
|
||||
end
|
||||
table.insert(exlist.third.white[host], rhost)
|
||||
end
|
||||
else
|
||||
if typ == "white" or typ == "black" then
|
||||
rpdb:exec(string.format(sql_format.add_list, typ, sql_escape(host)))
|
||||
else
|
||||
table.insert(exlist.white, host)
|
||||
end
|
||||
end
|
||||
suc = "sucess"
|
||||
end
|
||||
elseif cmd == "del" then
|
||||
if listed then
|
||||
if rhost then
|
||||
if typ == "white" or typ == "black" then
|
||||
rpdb:exec(string.format(sql_format.remove_tp_list_exact,
|
||||
typ, sql_escape(host), sql_escape(rhost)))
|
||||
else
|
||||
local i = util.table.hasitem(exlist.third.white[host] or {}, rhost)
|
||||
if i then table.remove(exlist.third.white[host], i) end
|
||||
end
|
||||
else
|
||||
if typ == "white" or typ == "black" then
|
||||
rpdb:exec(string.format(sql_format.remove_list, typ, sql_escape(host)))
|
||||
else
|
||||
local i = util.table.hasitem(exlist.white, host)
|
||||
if i then table.remove(exlist.white, i) end
|
||||
end
|
||||
end
|
||||
suc = "sucess"
|
||||
end
|
||||
end
|
||||
-- Feedback on sucess/failure
|
||||
if suc == "sucess" then
|
||||
-- Changed [typ]-list, clear cache
|
||||
cache = {}
|
||||
w:notify(string.format(retStr[suc][cmd][num][typ], host or "", rhost or ""))
|
||||
else
|
||||
w:error(string.format(retStr[suc][cmd][num][typ], host or "", rhost or ""))
|
||||
end
|
||||
end
|
||||
|
||||
-- Master user commands parser
|
||||
local rp_command = function(command, w, a)
|
||||
a = string.lower(a or "")
|
||||
local args = util.string.split(util.string.strip(a or ""), " ")
|
||||
|
||||
if command == "set" then
|
||||
-- Set request policy behaviors
|
||||
local val = not string.match(args[1], "!$")
|
||||
local set = string.match(args[1], "(.*)!$") or args[1]
|
||||
if not rp_setting(set, val, w) then
|
||||
w:error("Policy: set '" .. args[1] .. "' is not a valid setting. (adblock[!], requestpolicy[!], typepolicy[!], acceptall[!], strictsubdomain[!])")
|
||||
end
|
||||
elseif command == "clear" then
|
||||
w:notify(string.format("Removed %d policy exceptions.", clear_exlist()))
|
||||
else
|
||||
-- else it's wl/bl/ex and args will be hosts and require special parsing
|
||||
if #args == 0 or #args > 2 then
|
||||
w:error("Policy: Wrong number of arguments!")
|
||||
return
|
||||
end
|
||||
-- Attempt to get a host/rhost out of args
|
||||
local host = args[1] and ((args[1] == "all" and "all") or (lousy.uri.parse(args[1]) or {}).host)
|
||||
local rhost = args[2] and ((args[2] == "all" and "all") or (lousy.uri.parse(args[2]) or {}).host)
|
||||
|
||||
-- Convert empty rhost to nil
|
||||
if rhost == "" then rhost = nil end
|
||||
--TODO add host/rhost cheking vs public suffixes with getdomain()
|
||||
if #args == 1 then
|
||||
if not host then
|
||||
w:error("Bad argument error. (" .. host .. ")")
|
||||
return
|
||||
end
|
||||
else
|
||||
if not host or not rhost then
|
||||
w:error("Bad argument error. (" .. host .. ", " .. rhost ..")")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if command == "wl" or command == "whitelist" then
|
||||
modList("add", "white", {host, rhost}, w)
|
||||
elseif command == "bl" or comamnd == "blacklist" then
|
||||
modList("add", "black", {host, rhost}, w)
|
||||
elseif command == "ex" or command == "exception" then
|
||||
modList("add", "ex", {host, rhost}, w)
|
||||
elseif command == "wl!" or command == "whitelist!" then
|
||||
modList("del", "white", {host, rhost}, w)
|
||||
elseif command == "bl!" or command == "blacklist!" then
|
||||
modList("del", "black", {host, rhost}, w)
|
||||
elseif command == "ex!" or command == "exception!" then
|
||||
modList("del", "ex", {host, rhost}, w)
|
||||
else
|
||||
w:error("Policy: '" .. command .. "' is not a valid request policy command!")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add commands ===============================================================
|
||||
new_mode("policymenu", {
|
||||
enter = function (w)
|
||||
local afg = theme.rpolicy_active_menu_fg or theme.proxy_active_menu_fg
|
||||
local ifg = theme.rpolicy_inactive_menu_fg or theme.proxy_inactive_menu_fg
|
||||
local abg = theme.rpolicy_active_menu_bg or theme.proxy_active_menu_bg
|
||||
local ibg = theme.rpolicy_inactive_menu_bg or theme.proxy_inactive_menu_bg
|
||||
|
||||
local template = ' Allowed: <span foreground = "#0f0">%2d</span> Blocked: <span foreground = "#f00">%2d</span> %s'
|
||||
local reason = { start = "[Reason(s):", ends = "]"}
|
||||
|
||||
local main = (lousy.uri.parse(w.view.uri) or {}).host or "about:config"
|
||||
local rows = {}
|
||||
local main_row
|
||||
for host,pol in pairs(navto[w.view].res) do
|
||||
-- Generate a list of reason why requests were blocked
|
||||
local reasons = ""
|
||||
for k,_ in pairs(pol.reasons) do
|
||||
reasons = reasons .. (k and " ") .. k
|
||||
end
|
||||
local notcdr = domainmatch(main, host)
|
||||
-- Underline the main domain of the host
|
||||
local domain = string.gsub(getdomain(host), "[%.%-]", "%%%1")
|
||||
local formhost = string.gsub(host, domain, "<u>" .. domain .. "</u>")
|
||||
if host == main then
|
||||
main_row = {
|
||||
" " .. formhost .. "", string.format(template, pol.accept ,pol.deny, ((reasons ~= "") and reason.start .. reasons .. reason.ends) or ""),
|
||||
host = host, pol = pol,
|
||||
fg = (notcdr and afg) or ifg,
|
||||
bg = ibg}
|
||||
else
|
||||
table.insert(rows, (notcdr and 1) or #rows +1,
|
||||
{ " " .. formhost .. "", string.format(template, pol.accept ,pol.deny, ((reasons ~= "") and reason.start .. reasons .. reason.ends) or ""),
|
||||
host = host, pol = pol,
|
||||
fg = (notcdr and afg) or ifg,
|
||||
bg = ibg,
|
||||
})
|
||||
end
|
||||
end
|
||||
-- Add main host to top of the list
|
||||
if main_row then
|
||||
table.insert(rows, 1, main_row)
|
||||
end
|
||||
-- Add title row entry
|
||||
table.insert(rows, 1, { "Domains requested by " .. main, "Actions Taken", title = true })
|
||||
w.menu:build(rows)
|
||||
w:notify("Use j/k to move, Enter to select a host and open actions submenu, or h to open policy help (and full list of actions).", false)
|
||||
end,
|
||||
|
||||
leave = function (w)
|
||||
w.menu:hide()
|
||||
end,
|
||||
})
|
||||
|
||||
local genLine = function ( fmt, cFmt, cm, h, rh, ifg, ibg)
|
||||
return {string.format(fmt, h, rh),
|
||||
string.format(cFmt, cm, h, rh),
|
||||
host = h, rhost = rh, cmd = cm,
|
||||
fg = ifg, bg = ibg}
|
||||
end
|
||||
|
||||
new_mode("policysubmenu", {
|
||||
enter = function (w)
|
||||
local ifg = theme.rpolicy_inactive_menu_fg or theme.inactive_menu_fg
|
||||
local ibg = theme.rpolicy_inactive_menu_bg or theme.inactive_menu_bg
|
||||
local host = navto[w.view].selectedhost or "REQ_HOST"
|
||||
local main = (lousy.uri.parse(w.view.uri or "") or {}).host or "HOST"
|
||||
local rows = {{ "Actions for " .. host , "Command", title = true }}
|
||||
-- Any host
|
||||
if checkList("white", {host, nil}) then
|
||||
table.insert(rows, genLine("Remove %s from whitelist", " :rp %s %s", "wl!", host, nil, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Add %s to whitelist", " :rp %s %s", "wl", host, nil, ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("black", {host, nil}) then
|
||||
table.insert(rows, genLine("Remove %s from blacklist", " :rp %s %s", "bl!", host, nil, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Add %s to blacklist", " :rp %s %s", "bl", host, nil, ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("ex", {host, nil}) then
|
||||
table.insert(rows, genLine("Revoke exception for %s", " :rp %s %s", "ex!", host, nil, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Grant an exception for %s", " :rp %s %s", "ex", host, nil, ifg, ibg))
|
||||
end
|
||||
|
||||
-- For main host
|
||||
if host == main then
|
||||
if checkList("white", {host, "all"}) then
|
||||
table.insert(rows, genLine("Revoke complete CDR whitelisting from %s", " :rp %s %s %s", "wl!", host, "ALL", ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Allow all CDRs from %s", " :rp %s %s %s", "wl", host, "ALL", ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("black", {host, "all"}) then
|
||||
table.insert(rows, genLine("Revoke complete CDR blacklisting from %s", " :rp %s %s %s", "bl!", host, "ALL", ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Deny all CDRs from %s", " :rp %s %s %s", "bl", host, "ALL", ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("ex", {host, "all"}) then
|
||||
table.insert(rows, genLine("Revoke complete CDR exception from %s", " :rp %s %s %s", "ex!", host, "ALL", ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Grant an excpetion for all CDRs from %s", " :rp %s %s %s", "ex", host, "ALL", ifg, ibg))
|
||||
end
|
||||
|
||||
-- For other hosts
|
||||
else
|
||||
if checkList("white", {main, host}) then
|
||||
table.insert(rows, genLine("Revoke whitelisting of CDRs from %s to %s", " :rp %s %s %s", "wl!", main, host, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Allow CDRs from %s to %s", " :rp %s %s %s", "wl", main, host, ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("black", {main, host}) then
|
||||
table.insert(rows, genLine("Revoke whitelisting of CDRs from %s to %s", " :rp %s %s %s", "bl!", main, host, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Deny CDRs from %s to %s", " :rp %s %s %s", "bl", main, host, ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("white", {"all", host}) then
|
||||
table.insert(rows, genLine("Revoke whitelisting of CDRs from %s to %s", " :rp %s %s %s", "wl!", "ALL", host, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Allow CDRs from %s to %s", " :rp %s %s %s", "wl", "ALL", host, ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("black", {"all", host}) then
|
||||
table.insert(rows, genLine("Revoke whitelisting of CDRs from %s to %s", " :rp %s %s %s", "bl!", "ALL", host, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Deny CDRs from %s to %s", " :rp %s %s %s", "bl", "ALL", host, ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("ex", {main, host}) then
|
||||
table.insert(rows, genLine("Revoke exception for CDRs from %s to %s", " :rp %s %s %s", "ex!", main, host, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Grant an excpetion for CDRs from %s to %s", " :rp %s %s %s", "ex", main, host, ifg, ibg))
|
||||
end
|
||||
|
||||
if checkList("ex", {"all", host}) then
|
||||
table.insert(rows, genLine("Revoke exception for CDRs from %s to %s", " :rp %s %s %s", "ex!", "ALL", host, ifg, ibg))
|
||||
else
|
||||
table.insert(rows, genLine("Grant an excpetion for CDRs from %s to %s", " :rp %s %s %s", "ex", "ALL", host, ifg, ibg))
|
||||
end
|
||||
end
|
||||
|
||||
w.menu:build(rows)
|
||||
w:notify("Use j/k to move, Enter to execute action, S-Enter to edit command, or q to exit.", false)
|
||||
end,
|
||||
|
||||
leave = function (w)
|
||||
w.menu:hide()
|
||||
end,
|
||||
})
|
||||
|
||||
-- Adds keybindings for the policy menus
|
||||
local key = lousy.bind.key
|
||||
add_binds("policymenu", lousy.util.table.join({
|
||||
-- Select user agent
|
||||
key({}, "Return",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row then
|
||||
navto[w.view].selectedhost = row.host
|
||||
w:set_mode("policysubmenu")
|
||||
end
|
||||
end),
|
||||
-- Exit menu
|
||||
key({}, "q", function (w) w:set_mode() end),
|
||||
|
||||
}, menu_binds))
|
||||
|
||||
add_binds("policysubmenu", lousy.util.table.join({
|
||||
key({}, "Return",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row and row.cmd then
|
||||
w:set_mode()
|
||||
rp_command(row.cmd, w, (row.host or "") .. " " .. (row.rhost or ""))
|
||||
end
|
||||
end),
|
||||
key({"Shift"}, "Return",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row and row[2] then
|
||||
w:enter_cmd(util.string.strip(row[2]))
|
||||
end
|
||||
end),
|
||||
-- Exit menu
|
||||
key({}, "q", function (w) w:set_mode() end),
|
||||
|
||||
}, menu_binds))
|
||||
|
||||
-- Add ex-mode commands
|
||||
local cmd = lousy.bind.cmd
|
||||
add_cmds({
|
||||
cmd({"requestpolicy", "rp"}, "view current page requests",
|
||||
function (w, a)
|
||||
if not a then
|
||||
w:set_mode("policymenu")
|
||||
else
|
||||
-- if called with an argument, try to interprate the command
|
||||
local args = util.string.split(util.string.strip(a or ""), " ")
|
||||
local aa = string.match(a, ".- (.*)")
|
||||
rp_command(args[1], w, aa)
|
||||
end
|
||||
end),
|
||||
cmd({"rp-whitelist", "rp-wl"}, "add a whitelist entry",
|
||||
function(w, a, o)
|
||||
rp_command((o.bang and "wl!") or "wl", w, a)
|
||||
end),
|
||||
cmd({"rp-blacklist", "rp-bl"}, "add a blacklist entry",
|
||||
function(w, a, o)
|
||||
rp_command((o.bang and "bl!") or "bl", w, a)
|
||||
end),
|
||||
cmd({"rp-exception", "rp-ex"}, "grant temporary exceptions to request polices",
|
||||
function(w, a, o)
|
||||
rp_command((o.bang and "ex!") or "ex", w, a)
|
||||
end),
|
||||
cmd({"rp-set"}, "set request policy plugin behaviors",
|
||||
function(w, a)
|
||||
rp_command("set", w, a)
|
||||
end),
|
||||
cmd({"rp-clear"}, "clear request policy exceptions",
|
||||
function(w, a)
|
||||
rp_command("clear", w, a)
|
||||
end),
|
||||
})
|
||||
|
||||
-- Adds buffer command to invoke the policy menu and temp-allow all
|
||||
-- ,pp = open policy menu
|
||||
-- ,pa = allow all CDR from current host for this session
|
||||
-- ,pt = toggle CDR filtering
|
||||
local buf = lousy.bind.buf
|
||||
add_binds("normal", {
|
||||
buf("^,pp$", function (w) w:set_mode("policymenu") end),
|
||||
buf("^,pa$", function(w)
|
||||
if w.view and w.view.uri ~= "about:blank" then
|
||||
rp_command("ex", w, w.view.uri .. " all")
|
||||
end end),
|
||||
buf("^,pt$", function (w) rp_setting("requestpolicy", "toggle" ,w) end),
|
||||
})
|
||||
|
||||
-- Status Bar Widget ==========================================================
|
||||
-- Create the indictor widget on window creation
|
||||
window.init_funcs.build_policy_indicator = function(w)
|
||||
local i = w.sbar.r
|
||||
i.policy = widget{type="label"}
|
||||
i.layout:pack(w.sbar.r.policy)
|
||||
i.layout:reorder(w.sbar.r.policy, 1)
|
||||
i.policy.fg = theme.buf_sbar_fg
|
||||
i.policy.font = theme.buf_sbar_font
|
||||
w:update_policy()
|
||||
-- Update indicator on tab change
|
||||
w.tabs:add_signal("switch-page", function (_,view)
|
||||
capi.luakit.idle_add(function() w:update_policy(w) return false end)
|
||||
end)
|
||||
end
|
||||
|
||||
-- Update indicator on page navigation
|
||||
webview.init_funcs.policy_update = function(view, w)
|
||||
view:add_signal("load-status", function (v, status)
|
||||
if status == "committed" or status == "provisional" then
|
||||
w:update_policy(false)
|
||||
elseif status == "failed" or status == "finished" then
|
||||
w:update_policy(true)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Update contents of request policy widget
|
||||
window.methods.update_policy = function(w, fin)
|
||||
if not w.view then return end
|
||||
local pw = w.sbar.r.policy
|
||||
if filtering.widget then
|
||||
local text
|
||||
if not fin then
|
||||
text = "[Loading...]"
|
||||
else
|
||||
text = "["
|
||||
if navto[w.view].res then
|
||||
local acc, rej = 0, 0
|
||||
for _,pol in pairs(navto[w.view].res) do
|
||||
acc = acc + pol.accept
|
||||
rej = rej + pol.deny
|
||||
end
|
||||
text = text .. string.format("<span foreground=\"#0f0\">A%d</span> <span foreground=\"#f00\">B%d</span>", acc, rej)
|
||||
end
|
||||
text = text .. "]"
|
||||
end
|
||||
pw.text = text
|
||||
pw:show()
|
||||
else
|
||||
pw:hide()
|
||||
end
|
||||
end
|
||||
-- Call load()
|
||||
load()
|
@ -0,0 +1,89 @@
|
||||
-------------------------------------------------------------------------------
|
||||
-- --
|
||||
-- Blocks Adding "Private Browsing" Hosts to History DB --
|
||||
-- --
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local string = string
|
||||
local window = window
|
||||
local webview = webview
|
||||
local widget = widget
|
||||
local theme = theme
|
||||
local luakit = luakit
|
||||
local domain_props = domain_props
|
||||
local lousy = require("lousy")
|
||||
local util = lousy.util
|
||||
local history = require("history")
|
||||
local nohist = globals.history_blacklist or {}
|
||||
|
||||
local print = print
|
||||
module("plugins.private_browsing")
|
||||
|
||||
local indicator = { private = "!hist", notprivate = "" }
|
||||
|
||||
-- Load themes, if undefined fallback
|
||||
theme.pbm_font = theme.pbm_font or theme.buf_sbar_font
|
||||
theme.pbm_fg = theme.pbm_fg or theme.buf_sbar_fg
|
||||
theme.pbm_bg = theme.pbm_bg or theme.buf_sbar_bg
|
||||
|
||||
-- Create the indictor widget on window creation
|
||||
window.init_funcs.build_pindicator = function(w)
|
||||
local i = w.sbar.r
|
||||
i.prvt = widget{type="label"}
|
||||
i.layout:pack(w.sbar.r.prvt)
|
||||
i.layout:reorder(w.sbar.r.prvt, 2)
|
||||
i.prvt.font = theme.buf_sbar_font
|
||||
i.prvt.fg = theme.buf_sbar_fg
|
||||
w:update_prvt()
|
||||
-- Update indicator on tab change
|
||||
w.tabs:add_signal("switch-page", function (_,view)
|
||||
luakit.idle_add(function() w:update_prvt(w) return false end)
|
||||
end)
|
||||
end
|
||||
|
||||
-- Update indicator on page navigation
|
||||
webview.init_funcs.prvt_update = function(view, w)
|
||||
view:add_signal("load-status", function (v, status)
|
||||
if status == "comitted" or status == "failed" or status == "finished" then
|
||||
w:update_prvt()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Updates widget based on status
|
||||
window.methods.update_prvt = function(w)
|
||||
if not w.view then return end
|
||||
local private_br = w.view.enable_private_browsing
|
||||
|
||||
local domain = (lousy.uri.parse(w.view.uri) or {}).host or ""
|
||||
domain = string.match(domain, "^www%.(.+)") or domain
|
||||
repeat
|
||||
private_br = private_br or util.table.hasitem(nohist, domain)
|
||||
domain = string.match(domain, "%.(.+)")
|
||||
until not domain
|
||||
|
||||
local prvt = w.sbar.r.prvt
|
||||
-- Set widget text based on privacy setting
|
||||
prvt.text = (private_br and indicator.private) or indicator.notprivate
|
||||
-- Hide blank widget
|
||||
if string.len(prvt.text) then
|
||||
prvt:show()
|
||||
else
|
||||
prvt:hide()
|
||||
end
|
||||
end
|
||||
|
||||
-- Hook to intercept history additions
|
||||
history.add_signal("add", function (uri, title)
|
||||
local domain = lousy.uri.parse(uri).host
|
||||
domain = string.match(domain or "", "^www%.(.+)") or domain or "all"
|
||||
-- Build list of domains and subdomains, pulling private browsing.
|
||||
-- I.e. for luakit.org load .luakit.org, luakit.org, .org
|
||||
local no_hist = domain_props.all.enable_private_browsing or (domain_props[domain] or {}).enable_private_browsing
|
||||
repeat
|
||||
no_hist = no_hist or (domain_props["."..domain] or {}).enable_private_browsing
|
||||
no_hist = no_hist or util.table.hasitem(nohist, domain)
|
||||
domain = string.match(domain, "%.(.+)")
|
||||
until not domain
|
||||
return not no_hist
|
||||
end)
|
@ -0,0 +1,343 @@
|
||||
------------------------------------------------------------
|
||||
-- Dynamic useragent settings --
|
||||
-- Written by lokichaos based upon proxy.lua by: --
|
||||
--
|
||||
-- Copyright © Piotr Husiatyński <phusiatynski@gmail.com> --
|
||||
------------------------------------------------------------
|
||||
|
||||
-- TODO
|
||||
-- make per-tab widget & add hooks to update it
|
||||
-- save ua in table
|
||||
-- clean table for GC pruning
|
||||
-- set behavior: set-current, set-all, set-new
|
||||
|
||||
-- Grab environment we need
|
||||
local io = io
|
||||
local os = os
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local error = error
|
||||
local string = string
|
||||
local lousy = require "lousy"
|
||||
local theme = theme
|
||||
local unpack = unpack
|
||||
local table = table
|
||||
local capi = { luakit = luakit, soup = soup }
|
||||
local webview = webview
|
||||
local widget = widget
|
||||
local window = window
|
||||
local util = lousy.util
|
||||
local globals = globals
|
||||
-- Check for mode/bind functions
|
||||
local add_binds, add_cmds = add_binds, add_cmds
|
||||
local new_mode, menu_binds = new_mode, menu_binds
|
||||
local setmetatable = setmetatable
|
||||
|
||||
module("plugin.useragent")
|
||||
|
||||
|
||||
-- Store each webview's ua-name
|
||||
local uas = {}
|
||||
setmetatable(uas, { __mode = "k" })
|
||||
|
||||
--- Module global variables
|
||||
local agents_file = capi.luakit.data_dir .. '/useragentmenu'
|
||||
|
||||
local useragents = {}
|
||||
local realagent = { name = 0, uastring = globals.useragent }
|
||||
local active = realagent
|
||||
local default_name = nil
|
||||
|
||||
-- Return ordered list of user agent names
|
||||
function get_names()
|
||||
return lousy.util.table.keys(useragents)
|
||||
end
|
||||
|
||||
-- Return ua string of user agent given by name
|
||||
function get(name)
|
||||
return useragents[name]
|
||||
end
|
||||
|
||||
--- Load user agents list from file
|
||||
-- @param fd_name custom user agent storage of nil to use default
|
||||
function load(fd_name)
|
||||
local fd_name = fd_name or agents_file
|
||||
if not os.exists(fd_name) then return end
|
||||
local strip = lousy.util.string.strip
|
||||
|
||||
for line in io.lines(fd_name) do
|
||||
local status, name, uastring = string.match(line, "^(.)%s(.+)%s\"(.+)\"$")
|
||||
if uastring then
|
||||
name, uastring = strip(name), strip(uastring)
|
||||
if status == '*' then
|
||||
active = { uastring = uastring, name = name }
|
||||
end
|
||||
useragents[name] = uastring
|
||||
end
|
||||
end
|
||||
-- Set saved default ua string
|
||||
globals.useragent = active.uastring
|
||||
default_name = active.name
|
||||
end
|
||||
|
||||
--- Save user agents list to file
|
||||
-- @param fd_name custom user agent storage of nil to use default
|
||||
function save(fd_name)
|
||||
local fd = io.open(fd_name or agents_file, "w")
|
||||
for name, uastring in pairs(useragents) do
|
||||
if uastrings ~= "" then
|
||||
local status = (active.name == name and '*') or ' '
|
||||
fd:write(string.format("%s %s \"%s\"\n", status, name, uastring))
|
||||
end
|
||||
end
|
||||
io.close(fd)
|
||||
end
|
||||
|
||||
--- Add new user agent to current list
|
||||
-- @param name user agent configuration name
|
||||
-- @param uastring user agent string
|
||||
-- @param save_file do not save configuration if false
|
||||
function set(name, uastring, save_file)
|
||||
local name = lousy.util.string.strip(name)
|
||||
if not string.match(name, "^([%w%p]+)$") then
|
||||
error("Invalid user agent name: " .. name)
|
||||
end
|
||||
useragents[name] = lousy.util.string.strip(uastring)
|
||||
if save_file ~= false then save() end
|
||||
end
|
||||
|
||||
--- Delete selected user agent from list
|
||||
-- @param name user agent name
|
||||
-- TODO check all tabs
|
||||
function del(name, w)
|
||||
local name = lousy.util.string.strip(name)
|
||||
if useragents[name] then
|
||||
-- if deleted user agent was the active one, use real/default uastring
|
||||
if name == active.name then
|
||||
active = realagent
|
||||
end
|
||||
useragents[name] = nil
|
||||
save()
|
||||
end
|
||||
end
|
||||
|
||||
--- Set given user agent to active. Return true on success, else false
|
||||
-- @param name user agents configuration name or nil to unset user agent.
|
||||
function set_active(name)
|
||||
if name ~= 0 then
|
||||
local name = lousy.util.string.strip(name)
|
||||
if not useragents[name] then
|
||||
error("Unknown user agent: " .. name)
|
||||
end
|
||||
active = { name = name, uastring = useragents[name] }
|
||||
else
|
||||
active = realagent
|
||||
end
|
||||
save()
|
||||
return true
|
||||
end
|
||||
|
||||
-- Create a user agent indicator widget and add it to the status bar
|
||||
window.init_funcs.build_ua_indicator = function (w)
|
||||
local r = w.sbar.r
|
||||
r.uai = widget{type="label"}
|
||||
r.layout:pack(r.uai)
|
||||
r.layout:reorder(r.uai, 2)
|
||||
r.uai.fg = theme.useragenti_sbar_fg or theme.sbar_fg
|
||||
r.uai.font = theme.useragenti_sbar_font or theme.sbar_font
|
||||
w.tabs:add_signal("switch-page", function (nbook, view, idx)
|
||||
capi.luakit.idle_add(function() w:update_ua_indicator() return false end)
|
||||
end)
|
||||
w:update_ua_indicator()
|
||||
end
|
||||
|
||||
-- Helper function to update text in user agent indicator
|
||||
window.methods.update_ua_indicator = function (w)
|
||||
local name = uas[w.view] or (uas[w.view] == 0 and 0) or default_name
|
||||
local uai = w.sbar.r.uai
|
||||
if name ~= 0 then
|
||||
local text = string.format("(%s)", name)
|
||||
if uai.text ~= text then uai.text = text end
|
||||
uai:show()
|
||||
else
|
||||
uai:hide()
|
||||
end
|
||||
end
|
||||
|
||||
new_mode("uagentmenu", {
|
||||
enter = function (w)
|
||||
-- Set all tab's uas entires
|
||||
for index = 1, w.tabs:count() do
|
||||
uas[w.tabs[index]] = uas[w.tabs[index]] or default_name
|
||||
end
|
||||
|
||||
local afg = theme.useragent_active_menu_fg or theme.proxy_active_menu_fg
|
||||
local ifg = theme.useragent_inactive_menu_fg or theme.proxy_inactive_menu_fg
|
||||
local abg = theme.useragent_active_menu_bg or theme.proxy_active_menu_bg
|
||||
local ibg = theme.useragent_inactive_menu_bg or theme.proxy_inactive_menu_bg
|
||||
|
||||
-- "Active" user agent, this is the one that is saved as a default between sessions
|
||||
local act_ua = uas[w.view]
|
||||
-- Add titlebar, and "Default" UA entry
|
||||
local dname = string.format(" %s %s%s", "Default Luakit User Agent",
|
||||
(active.name == 0 and "[Default]") or "",
|
||||
(default_name == 0 and "[Session]") or "")
|
||||
local rows = {{ "User Agent Name", " User Agent String", title = true },
|
||||
{ dname, " " .. realagent.uastring or "", name = 0, uastring = '',
|
||||
fg = (act_ua == 0 and afg) or ifg,
|
||||
bg = (act_ua == 0 and abg) or ibg},}
|
||||
|
||||
for _, name in ipairs(get_names()) do
|
||||
local uastring = get(name)
|
||||
local uaname = string.format(" %s %s%s", name,
|
||||
(active.name == name and "[Default]") or "",
|
||||
(default_name == name and "[Session]") or "")
|
||||
table.insert(rows, {
|
||||
uaname, " " .. uastring,
|
||||
name = name, uastring = lousy.util.escape(uastring),
|
||||
fg = (act_ua == name and afg) or ifg,
|
||||
bg = (act_ua == name and abg) or ibg,
|
||||
})
|
||||
end
|
||||
w.menu:build(rows)
|
||||
w:notify("Use j/k to move, [d]elete, [e]dit, [a]dd, [S]et default, [s]et for all tabs, [n] set for new tabs, return to set for current tab.", false)
|
||||
end,
|
||||
|
||||
leave = function (w)
|
||||
w.menu:hide()
|
||||
end,
|
||||
})
|
||||
|
||||
local cmd = lousy.bind.cmd
|
||||
add_cmds({
|
||||
cmd({"agent", "ua"}, "add new or select useragent",
|
||||
function (w, a)
|
||||
if not a then
|
||||
w:set_mode("uagentmenu")
|
||||
else
|
||||
local name, uastring = string.match(a, "(.+)%s\"(.+)\"")
|
||||
if name and uastring then
|
||||
set(name, uastring)
|
||||
else
|
||||
w:error("Bad usage. Correct format :agent <name> \"<agent string>\"")
|
||||
end
|
||||
end
|
||||
end),
|
||||
})
|
||||
|
||||
|
||||
local ua_set = function(mode, ua, w)
|
||||
if mode == "current" then
|
||||
w.view.user_agent = ua.uastring or realagent.uastring
|
||||
uas[w.view] = ua.name
|
||||
if ua.name ~= 0 then
|
||||
w:notify(string.format("Set user agent on this tab to: %s (%s).", ua.name, ua.uastring))
|
||||
else
|
||||
w:notify("Set user agent for current tab to default.")
|
||||
end
|
||||
|
||||
elseif mode == "newtabs" then
|
||||
globals.useragent = ua.uastring
|
||||
default_name = ua.name
|
||||
if ua.name ~= 0 then
|
||||
w:notify(string.format("Set user agent for all new tabs to: %s (%s).", ua.name, ua.uastring))
|
||||
else
|
||||
w:notify("Set user agent for all new tabs to default Luakit.")
|
||||
end
|
||||
|
||||
elseif mode == "all" then
|
||||
-- New Tabs will use this
|
||||
globals.useragent = ua.uastring
|
||||
default_name = ua.name
|
||||
-- Set user agent for all existing tabs
|
||||
for index = 1, w.tabs:count() do
|
||||
w.tabs[index].user_agent = ua.uastring
|
||||
uas[w.tabs[index]] = ua.name
|
||||
end
|
||||
if ua.name ~= 0 then
|
||||
w:notify(string.format("Set user agent for all tabs to: %s (%s).", ua.name, ua.uastring))
|
||||
else
|
||||
w:notify("Set user agent for all tabs to default.")
|
||||
end
|
||||
|
||||
elseif mode == "default" then
|
||||
globals.useragent = ua.uastring
|
||||
default_name = ua.name
|
||||
set_active(ua.name)
|
||||
if ua.name ~= 0 then
|
||||
w:notify(string.format("Set %s as default useragent (%s)", ua.name, ua.uastring))
|
||||
else
|
||||
w:notify("Unset default useragent, will default to real Luakit one.")
|
||||
end
|
||||
|
||||
end
|
||||
-- Update useragent statusbar widget
|
||||
w:update_ua_indicator()
|
||||
end
|
||||
|
||||
local key = lousy.bind.key
|
||||
add_binds("uagentmenu", lousy.util.table.join({
|
||||
-- Select user agent
|
||||
key({}, "Return",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row then
|
||||
w:set_mode()
|
||||
ua_set("current", row, w)
|
||||
end
|
||||
end),
|
||||
key({}, "S",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row then
|
||||
w:set_mode()
|
||||
ua_set("default", row, w)
|
||||
end
|
||||
end),
|
||||
key({}, "s",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row then
|
||||
w:set_mode()
|
||||
ua_set("all", row, w)
|
||||
end
|
||||
end),
|
||||
key({}, "n",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row then
|
||||
w:set_mode()
|
||||
ua_set("newtabs", row, w)
|
||||
end
|
||||
end),
|
||||
-- Delete user agent
|
||||
key({}, "d",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row and row.name then
|
||||
del(row.name)
|
||||
w.menu:del()
|
||||
end
|
||||
end),
|
||||
|
||||
-- Edit user agent
|
||||
key({}, "e",
|
||||
function (w)
|
||||
local row = w.menu:get()
|
||||
if row and row.name then
|
||||
w:enter_cmd(string.format(":agent %s \"%s\"", row.name, row.uastring))
|
||||
end
|
||||
end),
|
||||
|
||||
-- New user agent
|
||||
key({}, "a", function (w) w:enter_cmd(":agent ") end),
|
||||
|
||||
-- Exit menu
|
||||
key({}, "q", function (w) w:set_mode() end),
|
||||
|
||||
}, menu_binds))
|
||||
|
||||
-- Initialize module
|
||||
load()
|
||||
|
||||
-- vim: et:sw=4:ts=8:sts=4
|
@ -0,0 +1,10 @@
|
||||
camino "Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.6; en; rv:1.9.2.14pre) Gecko/20101212 Camino/2.1a1pre (like Firefox/3.6.14pre)"
|
||||
googlebot "Googlebot/2.1 ( http://www.googlebot.com/bot.html)"
|
||||
firefox15 "Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120427 Firefox/15.0a1"
|
||||
safari "Mozilla/5.0 (Macintosh; PPC Mac OS X 10_7_3) AppleWebKit/534.55.3 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10"
|
||||
inferfox "Mozilla/6.0 (compatible; AppleWebKit/latest; like Gecko/20120405; };-> infernal_edition:goto-hell) Firefox/666"
|
||||
firefox11 "Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko Firefox/11.0"
|
||||
firefox13 "Mozilla/5.0 (Windows NT 6.1; rv:12.0) Gecko/20120403211507 Firefox/12.0"
|
||||
ie10 "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)"
|
||||
firefox14 "Mozilla/5.0 (Windows NT 6.1; rv:14.0) Gecko/20120405 Firefox/14.0a1"
|
||||
opera10 "Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.10"
|
Binary file not shown.
@ -0,0 +1 @@
|
||||
macro pager \cb <pipe-entry>'urlview'<enter> 'Follow links with urlview'
|
@ -0,0 +1 @@
|
||||
text/html; w3m -I %{charset} -T text/html; copiousoutput;
|
@ -0,0 +1,39 @@
|
||||
source "gpg -dq ~/.my-pwds.gpg |"
|
||||
|
||||
set realname = "Dustin Swan"
|
||||
set imap_user = "dustinswan@gmail.com"
|
||||
set imap_pass = $my_pw_personal
|
||||
set folder = "imaps://imap.gmail.com/"
|
||||
set spoolfile = +INBOX
|
||||
set imap_check_subscribed
|
||||
set header_cache = ~/.mutt/hcache
|
||||
set record = "+[Gmail]/Sent Mail"
|
||||
set postponed = "+[Gmail]/Drafts"
|
||||
unset imap_passive
|
||||
set imap_keepalive = 300
|
||||
set mail_check = 60
|
||||
set smtp_url = "smtp://dustinswan@smtp.gmail.com:587/"
|
||||
set smtp_pass = $my_pw_personal
|
||||
|
||||
# Sorting
|
||||
set sort = threads
|
||||
set sort_aux = reverse-last-date-received
|
||||
|
||||
# Sidebar
|
||||
set sidebar_delim = ' │'
|
||||
set sidebar_visible = yes
|
||||
set sidebar_width = 24
|
||||
#color sidebar_new color221 color233
|
||||
|
||||
bind index <down> sidebar-next
|
||||
bind index <up> sidebar-prev
|
||||
bind index <right> sidebar-open
|
||||
|
||||
# Status Bar
|
||||
#set status_chars = " *&A"
|
||||
#set status_format = "---[ Folder: %f ]---[%r%n messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]---%>-%?p?( %p postponed )?---""
|
||||
|
||||
# Fucking html mail
|
||||
auto_view text/html
|
||||
alternative_order text/plain text/enriched text/html
|
||||
|
Loading…
Reference in New Issue