2015-10-29 12:00:41 +03:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
from PyQt5.QtGui import QIcon
|
|
|
|
from PyQt5.QtWidgets import (QAction, QApplication, QCheckBox, QComboBox,
|
|
|
|
QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit,
|
|
|
|
QMessageBox, QMenu, QPushButton, QSpinBox, QStyle, QSystemTrayIcon,
|
|
|
|
QTextEdit, QVBoxLayout)
|
2015-10-31 20:38:11 +03:00
|
|
|
from PyQt5.QtCore import (QThread, QTimer, QFile, QSettings)
|
2015-10-29 12:00:41 +03:00
|
|
|
import imaplib
|
2015-10-31 20:38:11 +03:00
|
|
|
imaplib._MAXLINE = 400000
|
2015-10-29 12:00:41 +03:00
|
|
|
import subprocess
|
|
|
|
import res
|
2015-10-31 20:38:11 +03:00
|
|
|
from ui_settings import Ui_Settings
|
|
|
|
from PyQt5 import QtCore, QtGui, QtWidgets
|
|
|
|
import os
|
|
|
|
import socket
|
|
|
|
import hashlib, uuid
|
2015-10-29 12:00:41 +03:00
|
|
|
|
|
|
|
#variables
|
|
|
|
timers = []
|
|
|
|
programTitle = "Mail Notifier"
|
2015-11-01 12:53:01 +03:00
|
|
|
settings = QSettings(os.path.expanduser("~")+"/.config/mail-notifier/settings.conf", QSettings.NativeFormat)
|
2015-10-31 20:38:11 +03:00
|
|
|
def SettingsExist():
|
|
|
|
if ((settings.contains("CheckInterval") and settings.value("CheckInterval") != "") and
|
|
|
|
(settings.contains("Notify") and settings.value("Notify") != "") and
|
|
|
|
(settings.contains("MailServer") and settings.value("MailServer") != "") and
|
|
|
|
(settings.contains("Port") and settings.value("Port") != "") and
|
|
|
|
(settings.contains("Login") and settings.value("Login") != "") and
|
|
|
|
(settings.contains("Password") and settings.value("Password") != "") and
|
|
|
|
(settings.contains("SSL") and settings.value("SSL") != "")):
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
2015-10-29 12:00:41 +03:00
|
|
|
|
|
|
|
class Window(QDialog):
|
|
|
|
def __init__(self):
|
|
|
|
super(Window, self).__init__()
|
|
|
|
|
|
|
|
# UI
|
|
|
|
self.createActions()
|
|
|
|
self.setTitle=programTitle
|
|
|
|
self.createTrayIcon()
|
|
|
|
self.trayIcon.setIcon(QIcon(":icons/mailbox_empty.png"))
|
|
|
|
self.trayIcon.setToolTip("You have no unread letters")
|
|
|
|
self.trayIcon.show()
|
2015-10-31 20:38:11 +03:00
|
|
|
|
|
|
|
# setup settings
|
|
|
|
self.ui = Ui_Settings()
|
|
|
|
self.ui.setupUi(self)
|
|
|
|
self.setWindowIcon(QIcon(os.path.dirname(os.path.realpath(__file__))+"/icons/mailbox_empty.png"))
|
|
|
|
self.SettingsRestore()
|
|
|
|
|
|
|
|
self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Ok).clicked.connect(self.btnOK_clicked)
|
|
|
|
self.ui.buttonBox.button(QtWidgets.QDialogButtonBox.Cancel).clicked.connect(self.btnCancel_clicked)
|
|
|
|
self.ui.btnTestConnection.clicked.connect(self.btnTestConnection_clicked)
|
2015-10-29 12:00:41 +03:00
|
|
|
# Menu actions
|
|
|
|
def createActions(self):
|
|
|
|
self.quitAction = QAction(QIcon(':icons/menu_quit.png'),"&Quit", self,
|
|
|
|
triggered=QApplication.instance().quit)
|
|
|
|
self.checkNow = QAction(QIcon(':icons/check_now.png'),"&Check now", self,
|
2015-10-31 20:38:11 +03:00
|
|
|
triggered=mail_check)
|
|
|
|
self.restoreAction = QAction(QIcon(":icons/settings.png"),"&Settings", self,
|
|
|
|
triggered=self.showNormal)
|
2015-10-29 12:00:41 +03:00
|
|
|
|
|
|
|
# UI functions
|
|
|
|
def createTrayIcon(self):
|
|
|
|
self.trayIconMenu = QMenu(self)
|
|
|
|
self.trayIconMenu.addAction(self.checkNow)
|
2015-10-31 20:38:11 +03:00
|
|
|
self.trayIconMenu.addAction(self.restoreAction)
|
2015-10-29 12:00:41 +03:00
|
|
|
self.trayIconMenu.addAction(self.quitAction)
|
|
|
|
self.trayIcon = QSystemTrayIcon(self)
|
|
|
|
self.trayIcon.setContextMenu(self.trayIconMenu)
|
|
|
|
|
2015-10-31 20:38:11 +03:00
|
|
|
def SettingsRestore(self):
|
|
|
|
if SettingsExist():
|
|
|
|
self.ui.checkFreq.setValue(int(settings.value("CheckInterval")))
|
|
|
|
self.ui.boolifNotify.setChecked(bool(settings.value("Notify")))
|
|
|
|
self.ui.txtboxMailServer.setText(settings.value("MailServer"))
|
|
|
|
self.ui.txtboxPort.setText(settings.value("Port"))
|
|
|
|
self.ui.txtboxLogin.setText(settings.value("Login"))
|
|
|
|
self.ui.txtboxPassword.setText(settings.value("Password"))
|
|
|
|
self.ui.boolifSSL.setChecked(bool(settings.value("SSL")))
|
|
|
|
def SettingsSave(self):
|
|
|
|
settings.setValue("CheckInterval",self.ui.checkFreq.value())
|
|
|
|
settings.setValue("Notify", self.ui.boolifNotify.isChecked())
|
|
|
|
settings.setValue("MailServer",self.ui.txtboxMailServer.text())
|
|
|
|
settings.setValue("Port",self.ui.txtboxPort.text())
|
|
|
|
settings.setValue("Login",self.ui.txtboxLogin.text())
|
|
|
|
settings.setValue("Password",self.ui.txtboxPassword.text())
|
|
|
|
settings.setValue("SSL",self.ui.boolifSSL.isChecked())
|
2015-10-29 12:00:41 +03:00
|
|
|
|
2015-10-31 20:38:11 +03:00
|
|
|
def btnOK_clicked(self):
|
|
|
|
self.SettingsSave()
|
|
|
|
|
|
|
|
if (settings.value("MailServer") == "" or settings.value("Port") == "" or settings.value("Login") == "" or settings.value("Password") == ""):
|
|
|
|
QMessageBox.critical(self, "Warning","You should fill all fields in IMAP settings!")
|
|
|
|
self.show()
|
|
|
|
mail_check()
|
|
|
|
self.ui.lblTestOutput.setText("")
|
|
|
|
|
|
|
|
def btnCancel_clicked(self):
|
|
|
|
self.SettingsRestore()
|
|
|
|
self.ui.lblTestOutput.setText("")
|
|
|
|
|
|
|
|
def btnTestConnection_clicked(self):
|
|
|
|
try:
|
|
|
|
if self.ui.boolifSSL.isChecked:
|
|
|
|
self.imap = imaplib.IMAP4_SSL(self.ui.txtboxMailServer.text(), self.ui.txtboxPort.text())
|
|
|
|
else:
|
|
|
|
self.imap = imaplib.IMAP4(self.ui.txtboxMailServer.text(), self.ui.txtboxPort.text())
|
|
|
|
self.imap.login(self.ui.txtboxLogin.text(), self.ui.txtboxPassword.text())
|
|
|
|
output = "Connection was established successfully"
|
|
|
|
except:
|
|
|
|
output = "Unable to establish connection to mailbox"
|
|
|
|
finally:
|
|
|
|
self.ui.lblTestOutput.setText(output)
|
2015-10-29 12:00:41 +03:00
|
|
|
|
|
|
|
def closeEvent(self, event):
|
|
|
|
print ("Closing the app")
|
2015-10-31 20:38:11 +03:00
|
|
|
|
2015-10-29 12:00:41 +03:00
|
|
|
# Common functions
|
2015-10-31 20:38:11 +03:00
|
|
|
|
2015-10-29 12:00:41 +03:00
|
|
|
class Mail():
|
|
|
|
def __init__(self):
|
2015-10-31 20:38:11 +03:00
|
|
|
socket.setdefaulttimeout(5)
|
|
|
|
self.user = settings.value("Login")
|
|
|
|
self.password = settings.value("Password")
|
|
|
|
self.mailserver = settings.value("MailServer")
|
|
|
|
self.port = settings.value("Port")
|
|
|
|
|
|
|
|
def login(self):
|
|
|
|
try:
|
|
|
|
if settings.value("SSL"):
|
|
|
|
self.imap = imaplib.IMAP4_SSL(self.mailserver, self.port)
|
|
|
|
|
|
|
|
else:
|
|
|
|
self.imap = imaplib.IMAP4(self.mailserver, self.port)
|
|
|
|
self.imap.login(self.user, self.password)
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
print("Login error")
|
|
|
|
return False
|
2015-10-29 12:00:41 +03:00
|
|
|
|
|
|
|
def checkMail(self):
|
2015-10-31 20:38:11 +03:00
|
|
|
try:
|
|
|
|
self.imap.select()
|
|
|
|
self.unRead = self.imap.search(None, 'UNSEEN')
|
|
|
|
return len(self.unRead[1][0].split())
|
|
|
|
except:
|
|
|
|
print("Unable to check mail")
|
|
|
|
return "ERROR"
|
2015-10-29 12:00:41 +03:00
|
|
|
|
|
|
|
def mail_check():
|
2015-10-31 20:38:11 +03:00
|
|
|
if SettingsExist():
|
|
|
|
m = Mail()
|
|
|
|
if m.login():
|
|
|
|
mail_count = m.checkMail()
|
|
|
|
if mail_count == 0:
|
|
|
|
window.trayIcon.setToolTip ("You have no unread mail")
|
|
|
|
window.trayIcon.setIcon(QIcon(":icons/mailbox_empty.png"))
|
|
|
|
else:
|
|
|
|
window.trayIcon.setToolTip ("You have "+ str(mail_count)+" unread letters")
|
|
|
|
window.trayIcon.setIcon(QIcon(":icons/mailbox_full.png"))
|
|
|
|
notify ("You have "+ str(mail_count) +" unread letters")
|
|
|
|
else:
|
|
|
|
window.trayIcon.setToolTip("Unable to establish connection to mailbox. Check your mail settings and make sure that you have not network problems.")
|
|
|
|
notify("Unable to establish connection to mailbox. Check your mail settings and make sure that you have not network problems.")
|
2015-10-29 12:00:41 +03:00
|
|
|
else:
|
2015-10-31 20:38:11 +03:00
|
|
|
window.trayIcon.setToolTip("Cannot find configuration file. You should give access to your mailbox")
|
2015-10-29 12:00:41 +03:00
|
|
|
def notify(message):
|
2015-10-31 20:38:11 +03:00
|
|
|
if settings.value("Notify"):
|
|
|
|
subprocess.Popen(['notify-send', programTitle, message])
|
2015-10-29 12:00:41 +03:00
|
|
|
return
|
2015-10-31 20:38:11 +03:00
|
|
|
|
|
|
|
def hash(password):
|
|
|
|
salt = uuid.uuid4().hex
|
|
|
|
return hashlib.sha512(password.encode('utf-8') + salt.encode('utf-8')).hexdigest()
|
2015-10-29 12:00:41 +03:00
|
|
|
|
|
|
|
class Thread(QThread):
|
|
|
|
def __init__(self):
|
|
|
|
QThread.__init__(self)
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
timer = QTimer()
|
|
|
|
timer.timeout.connect(mail_check)
|
2015-10-31 20:38:11 +03:00
|
|
|
if SettingsExist():
|
|
|
|
CheckInterval = 1000*60*int(settings.value("CheckInterval"))
|
|
|
|
else:
|
|
|
|
CheckInterval = 1000*60*5
|
|
|
|
timer.start(CheckInterval)
|
2015-10-29 12:00:41 +03:00
|
|
|
timers.append(timer)
|
|
|
|
|
|
|
|
self.exec_()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import sys
|
|
|
|
app = QApplication(sys.argv)
|
2015-11-12 17:39:44 +03:00
|
|
|
# Some DE are not response adequately on it, trying to ignore tray check
|
|
|
|
# if not QSystemTrayIcon.isSystemTrayAvailable():
|
|
|
|
# QMessageBox.critical(None, "Mail notifier",
|
|
|
|
# "I couldn't detect any system tray on this system.")
|
|
|
|
# sys.exit(1)
|
2015-10-29 12:00:41 +03:00
|
|
|
QApplication.setQuitOnLastWindowClosed(False)
|
|
|
|
window = Window()
|
2015-10-31 20:49:46 +03:00
|
|
|
if SettingsExist():
|
2015-10-31 20:38:11 +03:00
|
|
|
window.hide()
|
|
|
|
else:
|
|
|
|
window.show()
|
2015-10-29 12:00:41 +03:00
|
|
|
# UI started. Starting required functions after UI start
|
|
|
|
mail_check()
|
|
|
|
thread_instance = Thread()
|
|
|
|
thread_instance.start()
|
|
|
|
sys.exit(app.exec_())
|