mass commit:

added single/summary notification modes
support for GNOME 3 notification counter (single mode only)
added button to mark mails as read (single mode only)
removed open-in-mailreader and close buttons
removed unused code and some comments
removed unused config settings
fixed program termination and cleanup
fixed some potential multithreading issues
refactored config stuff
other minor refactoring
This commit is contained in:
Patrick Ulbrich
2011-11-06 20:41:24 +01:00
parent c62ba44000
commit ca89f0d1b8
4 changed files with 359 additions and 258 deletions

85
Mailnag/config.py Normal file
View File

@@ -0,0 +1,85 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# config.py
#
# Copyright 2011 Patrick Ulbrich <zulu99@gmx.net>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
import os
import ConfigParser
import xdg.BaseDirectory as bd
mailnag_defaults = {
'general':
{
'mail_client' : "evolution",
'messagetray_label' : "mailnag",
'check_interval' : 5,
'notification_mode' : 0,
'remember' : 1,
'sender_format' : 1,
'playsound' : 1,
'soundfile' : 'mailnag.wav',
'autostart' : 1
},
'filter':
{
'filter_on' : 0,
'filter_text' : 'newsletter, viagra'
},
'script':
{
'script0_on' : 0,
'script1_on' : 0,
'script0_file' : '',
'script1_file' : '',
},
'account':
{
'on' : '',
'name' : '',
'server' : '',
'user' : '',
'imap' : '',
'folder' : '',
'port' : ''
}
}
cfg_folder = os.path.join(bd.xdg_config_home, "mailnag")
cfg_file = os.path.join(cfg_folder, "mailnag.cfg")
def cfg_exists():
return os.path.exists(cfg_file)
def read_cfg():
cfg = ConfigParser.RawConfigParser()
cfg._sections = mailnag_defaults # HACK : use cfg.read_dict(mailnag_defaults) in python 3
if os.path.exists(cfg_file):
cfg.read(cfg_file)
return cfg
def write_cfg(cfg):
if not os.path.exists(cfg_folder):
os.popen("mkdir -p " + cfg_folder)
with open(cfg_file, 'wb') as configfile: cfg.write(configfile)

View File

@@ -25,13 +25,11 @@
PACKAGE_NAME = "mailnag"
from gi.repository import GLib, GdkPixbuf, Gtk, GObject
import os
import ConfigParser
import locale
import gettext
import xdg.BaseDirectory as bd
from utils import *
from config import read_cfg, write_cfg
from keyring import Keyring
from account_dialog import AccountDialog
@@ -63,11 +61,13 @@ class ConfigWindow:
self.window = builder.get_object("config_window")
self.window.set_icon(GdkPixbuf.Pixbuf.new_from_file_at_size(get_data_file("mailnag.svg"), 48, 48));
self.keyring = Keyring()
self.cfg = read_cfg()
#
# account tab
#
self.accounts = Accounts()
self.accounts = Accounts(self.cfg, self.keyring)
self.treeview_accounts = builder.get_object("treeview_accounts")
self.liststore_accounts = builder.get_object("liststore_accounts")
@@ -97,6 +97,10 @@ class ConfigWindow:
self.entry_mail_client = builder.get_object("entry_mail_client")
self.entry_label = builder.get_object("entry_label")
self.spinbutton_interval = builder.get_object("spinbutton_interval")
self.cb_notification_mode = builder.get_object("cb_notification_mode")
cell = Gtk.CellRendererText()
self.cb_notification_mode.pack_start(cell, True)
self.cb_notification_mode.add_attribute(cell, "text", 0)
self.chk_playsound = builder.get_object("chk_playsound")
self.chk_autostart = builder.get_object("chk_autostart")
@@ -127,32 +131,33 @@ class ConfigWindow:
def load_config(self):
self.entry_mail_client.set_text(cfg.get('general', 'mail_client'))
self.entry_label.set_text(cfg.get('general', 'messagetray_label'))
self.spinbutton_interval.set_value(int(cfg.get('general', 'check_interval')))
self.chk_playsound.set_active(int(cfg.get('general', 'playsound')))
self.chk_autostart.set_active(int(cfg.get('general', 'autostart')))
self.entry_mail_client.set_text(self.cfg.get('general', 'mail_client'))
self.entry_label.set_text(self.cfg.get('general', 'messagetray_label'))
self.spinbutton_interval.set_value(int(self.cfg.get('general', 'check_interval')))
self.cb_notification_mode.set_active(int(self.cfg.get('general', 'notification_mode')))
self.chk_playsound.set_active(int(self.cfg.get('general', 'playsound')))
self.chk_autostart.set_active(int(self.cfg.get('general', 'autostart')))
self.chk_enable_filter.set_active(int(cfg.get('filter', 'filter_on')))
self.textbuffer_filter.set_text(cfg.get('filter', 'filter_text'))
self.chk_enable_filter.set_active(int(self.cfg.get('filter', 'filter_on')))
self.textbuffer_filter.set_text(self.cfg.get('filter', 'filter_text'))
self.chk_script0.set_active(int(cfg.get('script', 'script0_on')))
self.chk_script0.set_active(int(self.cfg.get('script', 'script0_on')))
tmp = cfg.get('script', 'script0_file')
tmp = self.cfg.get('script', 'script0_file')
if len(tmp) > 0:
self.filechooser_script0.set_filename(tmp)
self.chk_script1.set_active(int(cfg.get('script', 'script1_on')))
self.chk_script1.set_active(int(self.cfg.get('script', 'script1_on')))
tmp = cfg.get('script', 'script1_file')
tmp = self.cfg.get('script', 'script1_file')
if len(tmp) > 0:
self.filechooser_script1.set_filename(tmp)
self.accounts.load()
if len(self.accounts.account) == 0:
imported_accounts = keyring.import_accounts()
imported_accounts = self.keyring.import_accounts()
if len(imported_accounts) > 0 and \
self.show_yesno_dialog(_("Mailnag found %s mail accounts on this computer.\n\nDo you want to import them?") % len(imported_accounts)):
for arr in imported_accounts:
@@ -167,43 +172,43 @@ class ConfigWindow:
def save_config(self):
cfg.set('general', 'mail_client', self.entry_mail_client.get_text())
cfg.set('general', 'messagetray_label', self.entry_label.get_text())
cfg.set('general', 'check_interval', int(self.spinbutton_interval.get_value()))
cfg.set('general', 'playsound',int(self.chk_playsound.get_active()))
self.cfg.set('general', 'mail_client', self.entry_mail_client.get_text())
self.cfg.set('general', 'messagetray_label', self.entry_label.get_text())
self.cfg.set('general', 'check_interval', int(self.spinbutton_interval.get_value()))
self.cfg.set('general', 'notification_mode', int(self.cb_notification_mode.get_active()))
self.cfg.set('general', 'playsound',int(self.chk_playsound.get_active()))
autostart = self.chk_autostart.get_active()
cfg.set('general', 'autostart', int(autostart))
self.cfg.set('general', 'autostart', int(autostart))
cfg.set('filter', 'filter_on', int(self.chk_enable_filter.get_active()))
self.cfg.set('filter', 'filter_on', int(self.chk_enable_filter.get_active()))
start, end = self.textbuffer_filter.get_bounds()
cfg.set('filter', 'filter_text', self.textbuffer_filter.get_text(start, end, True))
self.cfg.set('filter', 'filter_text', self.textbuffer_filter.get_text(start, end, True))
cfg.set('script', 'script0_on', int(self.chk_script0.get_active()))
self.cfg.set('script', 'script0_on', int(self.chk_script0.get_active()))
tmp = self.filechooser_script0.get_filename()
if tmp == None: tmp = ""
cfg.set('script', 'script0_file', tmp)
self.cfg.set('script', 'script0_file', tmp)
cfg.set('script', 'script1_on', int(self.chk_script1.get_active()))
self.cfg.set('script', 'script1_on', int(self.chk_script1.get_active()))
tmp = self.filechooser_script1.get_filename()
if tmp == None: tmp = ""
cfg.set('script', 'script1_file', tmp)
self.cfg.set('script', 'script1_file', tmp)
on, name, server, user, password, imap, folder, port = self.accounts.get_cfg()
cfg.set('account', 'on', on)
cfg.set('account', 'name', name)
cfg.set('account', 'server', server)
cfg.set('account', 'user', user)
cfg.set('account', 'imap', imap)
cfg.set('account', 'folder', folder)
cfg.set('account', 'port', port)
self.cfg.set('account', 'on', on)
self.cfg.set('account', 'name', name)
self.cfg.set('account', 'server', server)
self.cfg.set('account', 'user', user)
self.cfg.set('account', 'imap', imap)
self.cfg.set('account', 'folder', folder)
self.cfg.set('account', 'port', port)
for acc in self.accounts.account:
if bool(acc.imap): protocol = 'imap'
else: protocol = 'pop'
keyring.set(protocol, acc.user, acc.server, acc.password)
self.keyring.set(protocol, acc.user, acc.server, acc.password)
cfg_file = os.path.join(cfg_folder, "mailnag.cfg")
with open(cfg_file, 'wb') as configfile: cfg.write(configfile)
write_cfg(self.cfg)
if autostart: create_autostart()
else: delete_autostart()
@@ -342,7 +347,7 @@ class ConfigWindow:
def __save_and_quit(self):
self.save_config()
keyring.remove(self.accounts.account) # delete obsolete entries from Keyring
self.keyring.remove(self.accounts.account) # delete obsolete entries from Keyring
Gtk.main_quit()
@@ -371,10 +376,11 @@ class Account:
class Accounts:
def __init__(self):
def __init__(self, cfg, keyring):
self.account = []
self.current = None # currently selected account_id
self.cfg = cfg
self.keyring = keyring
def add(self, on = 0, name = _('Unnamed'), server = '', user= '' , \
password = '', imap = 0, folder = '', port = ''): # add one new account
@@ -395,13 +401,13 @@ class Accounts:
def load(self):
self.account = [] # empty account list
on = cfg.get('account', 'on')
name = cfg.get('account', 'name')
server = cfg.get('account', 'server')
user = cfg.get('account', 'user')
imap = cfg.get('account', 'imap')
folder = cfg.get('account', 'folder')
port = cfg.get('account', 'port')
on = self.cfg.get('account', 'on')
name = self.cfg.get('account', 'name')
server = self.cfg.get('account', 'server')
user = self.cfg.get('account', 'user')
imap = self.cfg.get('account', 'imap')
folder = self.cfg.get('account', 'folder')
port = self.cfg.get('account', 'port')
separator = '|'
on_list = on.split(separator)
@@ -423,7 +429,7 @@ class Accounts:
port = port_list[i]
if imap: protocol = 'imap'
else: protocol = 'pop'
password = keyring.get(protocol, user, server)
password = self.keyring.get(protocol, user, server)
self.add(on, name, server, user, password, imap, folder, port) # fill Account list
@@ -476,87 +482,9 @@ class Accounts:
return cfg_on, cfg_name, cfg_server, cfg_user, password_list, cfg_imap, cfg_folder, cfg_port
def ok(self, window): # check if name, server, user, password are not empty
nok = [] # list of not-ok accounts
for acc in self.account:
if acc.name == '' or \
acc.server == '' or \
acc.user == '' or \
acc.password == '':
nok.append(acc.name)
if len(nok) > 0:
message_text = _("Missing data in account(s):") + "\n\n"
for acc_name in nok:
message_text += acc_name + '\n'
message_text += "\n" + _("Please correct this first.")
window.show_message(message_text)
return False, nok
else:
return True, True
#
# Misc
#
def read_config(): # read config file or create it
cfg = ConfigParser.RawConfigParser()
cfg_file = cfg_file = os.path.join(cfg_folder, "mailnag.cfg")
if not os.path.exists(cfg_file): # create a fresh config file
print _("Config file does not exist, creating new one")
cfg = set_default_config(cfg) # write default values to cfg
with open(cfg_file, 'wb') as configfile: cfg.write(configfile)
cfg.read(cfg_file)
return cfg
def set_default_config(cfg):
try: cfg.add_section('general')
except ConfigParser.DuplicateSectionError: pass
cfg.set('general', 'mail_client', "evolution")
cfg.set('general', 'messagetray_label', "mailnag")
cfg.set('general', 'check_interval', 5)
cfg.set('general', 'show_only_new', 0)
cfg.set('general', 'remember', 1)
cfg.set('general', 'check_once', 0)
cfg.set('general', 'sender_format', 1)
cfg.set('general', 'playsound', 1)
cfg.set('general', 'soundfile', 'mailnag.wav')
cfg.set('general', 'autostart', 1)
try: cfg.add_section('filter')
except ConfigParser.DuplicateSectionError: pass
cfg.set('filter', 'filter_on', 0)
cfg.set('filter', 'filter_text', 'newsletter, viagra')
try: cfg.add_section('script')
except ConfigParser.DuplicateSectionError: pass
cfg.set('script', 'script0_on', 0)
cfg.set('script', 'script1_on', 0)
cfg.set('script', 'script2_on', 0)
cfg.set('script', 'script3_on', 0)
cfg.set('script', 'script4_on', 0)
cfg.set('script', 'script5_on', 0)
cfg.set('script', 'script0_file', '')
cfg.set('script', 'script1_file', '')
cfg.set('script', 'script2_file', '')
cfg.set('script', 'script3_file', '')
cfg.set('script', 'script4_file', '')
cfg.set('script', 'script5_file', '')
try: cfg.add_section('account')
except ConfigParser.DuplicateSectionError: pass
cfg.set('account', 'on', '')
cfg.set('account', 'name', '')
cfg.set('account', 'server', '')
cfg.set('account', 'user', '')
cfg.set('account', 'imap', '')
cfg.set('account', 'folder', '')
cfg.set('account', 'port', '')
return cfg
def create_autostart():
curdir = os.getcwd() # get working directory
exec_file = os.path.join(curdir, "mailnag") # path of the shell script to start mailnag.py
@@ -593,20 +521,9 @@ def delete_autostart():
# Entry point
#
def main():
global cfg, cfg_folder, keyring
set_procname("mailnag_config")
cfg_folder = os.path.join(bd.xdg_config_home, "mailnag")
if not os.path.exists(cfg_folder):
os.popen("mkdir -p " + cfg_folder)
cfg = read_config() # get configurations
keyring = Keyring()
confwin = ConfigWindow()
Gtk.main() # start main loop
Gtk.main()
if __name__ == "__main__": main()

View File

@@ -22,27 +22,24 @@
# MA 02110-1301, USA.
#
PACKAGE_NAME = "mailnag"
import poplib
import imaplib
import urllib2
import ConfigParser
import os
import subprocess
PACKAGE_NAME = "mailnag"
import threading
from gi.repository import GObject, GLib, GdkPixbuf, Gtk, Notify
import time
import email
from email.header import decode_header
import sys
import gettext
from config import read_cfg, cfg_exists, cfg_folder
from keyring import Keyring
from utils import *
import signal
import xdg.BaseDirectory as bd
gettext.bindtextdomain(PACKAGE_NAME, './locale')
gettext.textdomain(PACKAGE_NAME)
@@ -347,7 +344,7 @@ class Mails:
def in_filter(self, sendersubject): # check if filter appears in sendersubject
status = False
filter_text = cfg.get('filter', 'filter_text')
filter_list = filter_text.replace('\n', '').split(',') # convert text to list
filter_list = filter_text.replace('\n', '').split(',') # convert text to list
for filter_item in filter_list:
filter_stripped_item = filter_item.strip() # remove CR and white space
@@ -429,27 +426,24 @@ class Mails:
# Misc =================================================================
def read_config(cfg_file): # read config file or create it
cfg = ConfigParser.RawConfigParser()
if not os.path.exists(cfg_file):
print 'Error: Cannot find configuration file: ', cfg_file
exit(1)
def read_config():
if not cfg_exists():
return None
else:
cfg.read(cfg_file)
return cfg
return read_cfg()
def write_pid(): # write Mailnags's process id to file
pid_file = os.path.join(user_path, 'mailnag.pid')
def write_pid(): # write Mailnags's process id to file
pid_file = os.path.join(cfg_folder, 'mailnag.pid')
f = open(pid_file, 'w')
f.write(str(os.getpid())) # get PID and write to file
f.write(str(os.getpid()))
f.close()
def delete_pid(): # delete file mailnag.pid
pid_file = os.path.join(user_path, 'mailnag.pid')
def delete_pid(): # delete file mailnag.pid
pid_file = os.path.join(cfg_folder, 'mailnag.pid')
if os.path.exists(pid_file):
os.popen("rm " + pid_file) # delete it
os.popen("rm " + pid_file)
def user_scripts(event, data):
@@ -488,99 +482,151 @@ def commandExecutor(command, context_menu_command=None):
# MailChecker ============================================================
class MailChecker:
def __init__(self):
self.MAIL_LIST_LIMIT = 10 # prevent flooding of the messaging tray
self.mails = Mails() # create Mails object
self.reminder = Reminder() # create Reminder object
Notify.init(cfg.get('general', 'messagetray_label')) # initialize Notification
self.notification = Notify.Notification.new(" ", None, None) # empty string will emit a gtk warning
self.notification.set_hint("resident", GLib.Variant("b", True)) # don't close when the bubble or actions are clicked
self.notification.set_category("email")
self.notification.add_action("open", _("Open in mail reader"), self.__notification_action_handler, None, None)
self.notification.add_action("close", _("Close"), self.__notification_action_handler, None, None)
self.MAIL_LIST_LIMIT = 10 # prevent flooding of the messaging tray
self.mailcheck_lock = threading.Lock()
self.mails = Mails()
self.reminder = Reminder()
# dict that tracks all notifications that need to be closed
self.notifications = {}
Notify.init(cfg.get('general', 'messagetray_label')) # initialize Notification
def timeout(self, firstcheck = False):
print 'Checking email accounts at:', time.asctime() # debug
pid.kill() # kill all Zombies
with self.mailcheck_lock:
print 'Checking email accounts at:', time.asctime()
pid.kill() # kill all zombies
if firstcheck: # Manual firststart
self.reminder.load()
if firstcheck: # Manual firststart
self.reminder.load()
self.mail_list = self.mails.get_mail('desc') # get all mails from all inboxes
self.mail_list = self.mails.get_mail('desc') # get all mails from all inboxes
all_mails = len(self.mail_list)
new_mails = 0
summary = ""
body = ""
script_data = ""
unseen_mails = []
new_mails = []
for mail in self.mail_list:
if not self.reminder.contains(mail.id):
new_mails += 1
script_data += ' "<%s> %s"' % (mail.sender, mail.subject)
script_data = str(new_mails) + script_data
if all_mails == 0:
# no mails (e.g. email client has been launched) -> close notification
self.notification.close()
elif (firstcheck and all_mails > 0) or (new_mails > 0):
ubound = all_mails if all_mails <= self.MAIL_LIST_LIMIT else self.MAIL_LIST_LIMIT
script_data = ""
script_data_mailcount = 0
for i in range(ubound):
body += self.mail_list[i].sender + ":\n<i>" + self.mail_list[i].subject + "</i>\n\n"
for mail in self.mail_list:
if self.reminder.contains(mail.id): # mail was fetched before
if self.reminder.unseen(mail.id): # mail was not marked as seen
unseen_mails.append(mail)
if firstcheck: # first check after startup
new_mails.append(mail)
else: # mail is fetched the first time
unseen_mails.append(mail)
new_mails.append(mail)
script_data += ' "<%s> %s"' % (mail.sender, mail.subject)
script_data_mailcount += 1
if all_mails > self.MAIL_LIST_LIMIT:
body += "<i>" + _("(and {0} more)").format(str(all_mails - self.MAIL_LIST_LIMIT)) + "</i>"
script_data = str(script_data_mailcount) + script_data
if len(self.mail_list) == 0:
# no mails (e.g. email client has been launched) -> close notifications
for n in self.notifications.itervalues():
n.close()
self.notifications = {}
elif len(new_mails) > 0:
if cfg.get('general', 'notification_mode') == '1':
self.notify_summary(unseen_mails)
else:
self.notify_single(new_mails)
if all_mails > 1: # multiple new emails
summary = _("You have {0} new mails.").format(str(all_mails))
else:
summary = _("You have a new mail.")
if cfg.get('general', 'playsound') == '1': # play sound?
soundcommand = ['aplay', '-q', get_data_file(cfg.get('general', 'soundfile'))]
pid.append(subprocess.Popen(soundcommand))
if cfg.get('general', 'playsound') == '1': # play sound?
soundcommand = ['aplay', '-q', get_data_file(cfg.get('general', 'soundfile'))]
pid.append(subprocess.Popen(soundcommand))
self.reminder.save(self.mail_list)
self.notification.update(summary, body, "mail-unread")
self.notification.show()
user_scripts("on_mail_check", script_data) # process user scripts
self.reminder.save(self.mail_list)
sys.stdout.flush() # write stdout to log file
user_scripts("on_mail_check", script_data) # process user scripts
sys.stdout.flush() # write stdout to log file
return True
def __notification_action_handler(self, n, action, user_data):
self.notification.close()
if action == "open":
emailclient = cfg.get('general', 'mail_client').split(' ') # create list of command arguments
pid.append(subprocess.Popen(emailclient))
elif action == "close":
pass
def notify_summary(self, unseen_mails):
summary = ""
body = ""
def clear(self): # clear the messages list (not the menu entries)
show_only_new = bool(int(cfg.get('general', 'show_only_new'))) # get show_only_new flag
if len(self.notifications) == 0:
self.notifications['0'] = self.get_notification(" ", None, None) # empty string will emit a gtk warning
if show_only_new:
ubound = len(unseen_mails) if len(unseen_mails) <= self.MAIL_LIST_LIMIT else self.MAIL_LIST_LIMIT
for i in range(ubound):
body += unseen_mails[i].sender + ":\n<i>" + unseen_mails[i].subject + "</i>\n\n"
if len(unseen_mails) > self.MAIL_LIST_LIMIT:
body += "<i>" + _("(and {0} more)").format(str(len(unseen_mails) - self.MAIL_LIST_LIMIT)) + "</i>"
if len(unseen_mails) > 1: # multiple new emails
summary = _("You have {0} new mails.").format(str(len(unseen_mails)))
else:
summary = _("You have a new mail.")
self.notifications['0'].update(summary, body, "mail-unread")
self.notifications['0'].show()
def notify_single(self, new_mails):
for mail in new_mails:
n = self.get_notification(mail.sender, mail.subject, "mail-unread")
notification_id = str(id(n))
n.add_action("mark-as-read", _("Mark as read"), self.__notification_action_handler, (mail, notification_id), None)
n.show()
self.notifications[notification_id] = n
def get_notification(self, summary, body, icon):
n = Notify.Notification.new(summary, body, icon)
n.set_category("email")
n.add_action("default", "default", self.__notification_action_handler, None, None)
return n
def __notification_action_handler(self, n, action, user_data):
with self.mailcheck_lock:
if action == "default":
emailclient = cfg.get('general', 'mail_client').split(' ') # create list of command arguments
pid.append(subprocess.Popen(emailclient))
# clicking the notification bubble has closed all notifications
# so clear the reference array as well.
self.notifications = {}
elif action == "mark-as-read":
self.reminder.set_to_seen(user_data[0].id)
self.reminder.save(self.mail_list)
# clicking the action has closed the notification
# so remove its reference
del self.notifications[user_data[1]]
def clear(self):
with self.mailcheck_lock:
# mark all mails to seen
for mail in self.mail_list:
self.reminder.set_to_seen(mail.id)
self.reminder.save(self.mail_list) # save to mailnag.dat
else: # keep 'list' filled
self.mail_list = [] # clear mail list
self.reminder.save(self.mail_list)
# close all notifications
for n in self.notifications.itervalues():
n.close()
self.notifications = {}
self.mail_list = []
# Reminder =============================================================
class Reminder(dict):
def load(self): # load last known messages from mailnag.dat
remember = cfg.get('general', 'remember')
dat_file = os.path.join(user_path, 'mailnag.dat')
dat_file = os.path.join(cfg_folder, 'mailnag.dat')
we_have_a_file = os.path.exists(dat_file) # check if file exists
if remember == '1' and we_have_a_file:
f = open(dat_file, 'r') # open file again
@@ -595,7 +641,7 @@ class Reminder(dict):
def save(self, mail_list): # save mail ids to file
dat_file = os.path.join(user_path, 'mailnag.dat')
dat_file = os.path.join(cfg_folder, 'mailnag.dat')
f = open(dat_file, 'w') # open the file for overwrite
for m in mail_list:
try:
@@ -609,11 +655,7 @@ class Reminder(dict):
def contains(self, id): # check if mail id is in reminder list
try:
self[id]
return True
except KeyError:
return False
return (id in self)
def set_to_seen(self, id): # set seen flag for this email on True
@@ -626,10 +668,7 @@ class Reminder(dict):
def unseen(self, id): # return True if flag == '0'
try:
flag = self[id]
if flag == '0':
return True
else:
return False
return (flag == '0')
except KeyError:
return True
@@ -650,36 +689,48 @@ class Pid(list): # List class to manage subprocess PIDs
def cleanup():
# clean up resources
try:
mailchecker.notification.close()
for n in mailchecker.notifications.itervalues():
n.close()
except NameError: pass
delete_pid()
def sig_handler(signum, frame):
if mainloop != None:
mainloop.quit()
# Main =================================================================
def main():
global cfg, user_path, accounts, mails, mailchecker, pid
global mainloop, cfg, accounts, mails, mailchecker, pid
mainloop = None
set_procname("mailnag")
signal.signal(signal.SIGTERM, cleanup)
signal.signal(signal.SIGTERM, sig_handler)
try:
user_path = os.path.join(bd.xdg_config_home, "mailnag")
write_pid() # write Mailnag's process id to file
cfg = read_config(os.path.join(user_path, 'mailnag.cfg')) # get configuration from file
write_pid() # write Mailnag's process id to file
cfg = read_config()
if (cfg == None):
print 'Error: Cannot find configuration file. Please run mailnag_config first.'
exit(1)
accounts = Accounts() # create Accounts object
pid = Pid() # create Pid object
mailchecker = MailChecker() # create MailChecker object
mailchecker.timeout(True) # immediate check, firstcheck=True
if cfg.get('general', 'check_once') == '0': # wanna do more than one email check?
check_interval = int(cfg.get('general', 'check_interval'))
GObject.timeout_add_seconds(60 * check_interval, mailchecker.timeout)
Gtk.main() # start Loop
cleanup()
return 0
check_interval = int(cfg.get('general', 'check_interval'))
GObject.timeout_add_seconds(60 * check_interval, mailchecker.timeout)
mainloop = GObject.MainLoop()
mainloop.run()
except KeyboardInterrupt:
pass # ctrl+c pressed
finally:
cleanup()
if __name__ == '__main__': main()

View File

@@ -134,7 +134,7 @@
<property name="margin_right">6</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="n_rows">5</property>
<property name="n_rows">6</property>
<property name="n_columns">2</property>
<property name="column_spacing">6</property>
<property name="row_spacing">6</property>
@@ -150,8 +150,8 @@
</object>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="y_options"></property>
</packing>
</child>
@@ -233,8 +233,8 @@
</object>
<packing>
<property name="right_attach">2</property>
<property name="top_attach">4</property>
<property name="bottom_attach">5</property>
<property name="top_attach">5</property>
<property name="bottom_attach">6</property>
<property name="y_options"></property>
</packing>
</child>
@@ -254,8 +254,8 @@
</child>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
@@ -294,6 +294,40 @@
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<child>
<object class="GtkLabel" id="label15">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Notification mode:</property>
</object>
</child>
</object>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="cb_notification_mode">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="model">liststore_notification_mode</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
@@ -599,5 +633,19 @@ Copyright (c) 2011 Ralf Hersel</property>
<signal name="row-deleted" handler="liststore_accounts_row_deleted" swapped="no"/>
<signal name="row-inserted" handler="liststore_accounts_row_inserted" swapped="no"/>
</object>
<object class="GtkListStore" id="liststore_notification_mode">
<columns>
<!-- column-name gchararray1 -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0" translatable="yes">Single</col>
</row>
<row>
<col id="0" translatable="yes">Summary</col>
</row>
</data>
</object>
<object class="GtkTextBuffer" id="textbuffer_filter"/>
</interface>