dotfiles/awesome/widget/email/init.lua
2020-06-03 21:27:00 -05:00

413 lines
9.5 KiB
Lua

local awful = require('awful')
local gears = require('gears')
local wibox = require('wibox')
local naughty = require('naughty')
local beautiful = require('beautiful')
local dpi = beautiful.xresources.apply_dpi
local config_dir = gears.filesystem.get_configuration_dir()
local widget_icon_dir = config_dir .. 'widget/email/icons/'
local secrets = require('configuration.secrets')
local email_account = secrets.email.address
local app_password = secrets.email.app_password
local imap_server = secrets.email.imap_server
local port = secrets.email.port
local unread_email_count = 0
local startup_show = true
local scroll_container = function(widget)
return wibox.widget {
widget,
id = 'scroll_container',
max_size = 345,
speed = 75,
expand = true,
direction = 'h',
step_function = wibox.container.scroll
.step_functions.waiting_nonlinear_back_and_forth,
fps = 30,
layout = wibox.container.scroll.horizontal,
}
end
local email_icon_widget = wibox.widget {
{
id = 'icon',
image = widget_icon_dir .. 'email.svg',
resize = true,
forced_height = dpi(45),
forced_width = dpi(45),
widget = wibox.widget.imagebox,
},
layout = wibox.layout.fixed.horizontal
}
local email_from_text = wibox.widget {
font = 'SF Pro Text Bold 10',
markup = 'From:',
align = 'left',
valign = 'center',
widget = wibox.widget.textbox
}
local email_recent_from = wibox.widget {
font = 'SF Pro Text Regular 10',
markup = 'loading@stdout.sh',
align = 'left',
valign = 'center',
widget = wibox.widget.textbox
}
local email_subject_text = wibox.widget {
font = 'SF Pro Text Regular 10',
markup = 'Subject:',
align = 'left',
valign = 'center',
widget = wibox.widget.textbox
}
local email_recent_subject = wibox.widget {
font = 'SF Pro Text Regular 10',
markup = 'Loading data',
align = 'left',
valign = 'center',
widget = wibox.widget.textbox
}
local email_date_text = wibox.widget {
font = 'SF Pro Text Regular 10',
markup = 'Local Date:',
align = 'left',
valign = 'center',
widget = wibox.widget.textbox
}
local email_recent_date = wibox.widget {
font = 'SF Pro Text Regular 10',
markup = 'Loading date...',
align = 'left',
valign = 'center',
widget = wibox.widget.textbox
}
local email_report = wibox.widget{
{
{
layout = wibox.layout.fixed.horizontal,
spacing = dpi(10),
{
layout = wibox.layout.align.vertical,
expand = 'none',
nil,
email_icon_widget,
nil
},
{
layout = wibox.layout.align.vertical,
expand = 'none',
nil,
{
layout = wibox.layout.fixed.vertical,
{
email_from_text,
scroll_container(email_recent_from),
spacing = dpi(5),
layout = wibox.layout.fixed.horizontal
},
{
email_subject_text,
scroll_container(email_recent_subject),
spacing = dpi(5),
layout = wibox.layout.fixed.horizontal
},
{
email_date_text,
scroll_container(email_recent_date),
spacing = dpi(5),
layout = wibox.layout.fixed.horizontal
}
},
nil
}
},
margins = dpi(10),
widget = wibox.container.margin
},
forced_height = dpi(92),
bg = beautiful.groups_bg,
shape = function(cr, width, height)
gears.shape.partially_rounded_rect(cr, width, height, true, true, true, true, beautiful.groups_radius)
end,
widget = wibox.container.background
}
local email_details_tooltip = awful.tooltip
{
text = 'Loading...',
objects = {email_icon_widget},
mode = 'outside',
align = 'right',
preferred_positions = {'left', 'right', 'top', 'bottom'},
margin_leftright = dpi(8),
margin_topbottom = dpi(8)
}
local fetch_email_command = [[
python3 - <<END
import imaplib
import email
import datetime
import re
import sys
def process_mailbox(M):
rv, data = M.search(None, "(UNSEEN)")
if rv != 'OK':
print ("No messages found!")
return
for num in reversed(data[0].split()):
rv, data = M.fetch(num, '(BODY.PEEK[])')
if rv != 'OK':
print ("ERROR getting message", num)
return
msg = email.message_from_bytes(data[0][1])
print ('From:', msg['From'])
print ('Subject: %s' % (msg['Subject']))
date_tuple = email.utils.parsedate_tz(msg['Date'])
if date_tuple:
local_date = datetime.datetime.fromtimestamp(email.utils.mktime_tz(date_tuple))
print ("Local Date:", local_date.strftime("%a, %H:%M:%S %b %d, %Y") + "\n")
# with code below you can process text of email
# if msg.is_multipart():
# for payload in msg.get_payload():
# if payload.get_content_maintype() == 'text':
# print payload.get_payload()
# else:
# print msg.get_payload()
try:
M=imaplib.IMAP4_SSL("]] .. imap_server .. [[", ]] .. port .. [[)
M.login("]] .. email_account .. [[","]] .. app_password .. [[")
status, counts = M.status("INBOX","(MESSAGES UNSEEN)")
rv, data = M.select("INBOX")
if rv == 'OK':
unread = re.search(r'UNSEEN\s(\d+)', counts[0].decode('utf-8')).group(1)
print ("Unread Count: " + unread)
process_mailbox(M)
M.close()
M.logout()
except Exception as e:
if e:
print (e)
END
]]
local notify_all_unread_email = function(email_data)
local unread_counter = email_data:match('Unread Count: (.-)From:'):sub(1, -2)
local email_data = email_data:match('(From:.*)'):sub(1, -2)
local title = nil
if tonumber(unread_email_count) > 1 then
title = 'You have ' .. unread_counter .. ' unread emails!'
else
title = 'You have ' .. unread_counter .. ' unread email!'
end
naughty.notification ({
app_name = 'Email',
title = title,
message = email_data,
timeout = 30,
icon = widget_icon_dir .. 'email-unread.svg'
})
end
local notify_new_email = function(count, from, subject)
if not startup_show and (tonumber(count) > tonumber(unread_email_count)) then
unread_email_count = tonumber(count)
local message = "From: " .. from ..
"\nSubject: " .. subject
naughty.notification ({
app_name = 'Email',
title = 'You have a new unread email!',
message = message,
timeout = 10,
icon = widget_icon_dir .. 'email-unread.svg'
})
else
unread_email_count = tonumber(count)
end
end
local set_email_data_tooltip = function(email_data)
local email_data = email_data:match('(From:.*)')
local counter = "<span font='SF Pro Text Bold 10'>Unread Count: </span>" .. unread_email_count
email_details_tooltip:set_markup(counter .. '\n\n' .. email_data)
end
local set_widget_markup = function(from, subject, date, tooltip)
email_recent_from:set_markup(from:gsub('%\n', ''))
email_recent_subject:set_markup(subject:gsub('%\n', ''))
email_recent_date:set_markup(date:gsub('%\n', ''))
if tooltip then
email_details_tooltip:set_markup(tooltip)
end
end
local set_no_connection_msg = function()
set_widget_markup(
'message@stderr.sh',
'Check network connection!',
os.date("%d-%m-%Y %H:%M:%S"),
'No internet connection!'
)
end
local set_invalid_credentials_msg = function()
set_widget_markup(
'message@stderr.sh',
'Invalid Credentials!',
os.date("%d-%m-%Y %H:%M:%S"),
'You have an invalid credentials!'
)
end
local set_latest_email_data = function(email_data)
local unread_count = email_data:match('Unread Count: (.-)From:'):sub(1, -2)
local recent_from = email_data:match('From: (.-)Subject:'):sub(1, -2)
local recent_subject = email_data:match('Subject: (.-)Local Date:'):sub(1, -2)
local recent_date = email_data:match('Local Date: (.-)\n')
recent_from = recent_from:match('<(.*)>') or recent_from:match('&lt;(.*)&gt;') or recent_from
local count = tonumber(unread_count)
if count > 0 and count <= 9 then
email_icon_widget.icon:set_image(widget_icon_dir .. 'email-'.. tostring(count) .. '.svg')
elseif count > 9 then
email_icon_widget.icon:set_image(widget_icon_dir .. 'email-9+.svg')
end
set_widget_markup(
recent_from,
recent_subject,
recent_date
)
notify_new_email(unread_count, recent_from, recent_subject)
end
local set_empty_inbox_msg = function()
set_widget_markup(
'empty@stdout.sh',
'Empty inbox',
os.date("%d-%m-%Y %H:%M:%S"),
'Empty inbox.'
)
end
local fetch_email_data = function()
awful.spawn.easy_async_with_shell(
fetch_email_command,
function(stdout)
stdout = gears.string.xml_escape(stdout:sub(1, -2))
if stdout:match("Temporary failure in name resolution") then
set_no_connection_msg()
return
elseif stdout:match("Invalid credentials") then
set_invalid_credentials_msg()
return
elseif stdout:match("Unread Count: 0") then
email_icon_widget.icon:set_image(widget_icon_dir .. 'email.svg')
set_empty_inbox_msg()
return
elseif not stdout:match('Unread Count: (.-)From:') then
return
elseif not stdout or stdout == '' then
return
end
set_latest_email_data(stdout)
set_email_data_tooltip(stdout)
if startup_show then
notify_all_unread_email(stdout)
startup_show = false
end
end
)
end
local set_missing_secrets_msg = function()
set_widget_markup(
'message@stderr.sh',
'Credentials are missing!',
os.date("%d-%m-%Y %H:%M:%S"),
'Missing credentials!'
)
end
local check_secrets = function()
if email_account == '' or app_password == '' or imap_server == '' or port == '' then
set_missing_secrets_msg()
return
else
fetch_email_data()
end
end
check_secrets()
local update_widget_timer = gears.timer {
timeout = 30,
autostart = true,
call_now = true,
callback = function()
check_secrets()
end
}
email_report:connect_signal(
"mouse::enter",
function()
check_secrets()
end
)
awesome.connect_signal(
'system::wifi_connected',
function()
gears.timer.start_new(
5,
function()
check_secrets()
end
)
end
)
return email_report