def _set_gmail_credentials(self, password, cookies): self._gmail_cookies_key = password self._gmail_cookies = cookies if password and cookies: self._button_log_in.set_label(_("Logged in")) else: self._button_log_in.set_label(_("Log in to account"))
def _on_btn_info_clicked(self, widget): aboutdialog = Gtk.AboutDialog() aboutdialog.set_title(_("About %s") % PACKAGE_NAME.title()) aboutdialog.set_version(APP_VERSION) aboutdialog.set_program_name(PACKAGE_NAME.title()) aboutdialog.set_comments(_("An extensible mail notification daemon.")) aboutdialog.set_copyright( _("Copyright (c) 2011 - 2019 Patrick Ulbrich and contributors.")) aboutdialog.set_logo_icon_name("mailnag") aboutdialog.set_website("https://github.com/pulb/mailnag") aboutdialog.set_website_label(_("Homepage")) aboutdialog.set_license_type(Gtk.License.GPL_2_0) aboutdialog.set_authors([ "Patrick Ulbrich (maintainer)", "Edwin Smulders", "Freeroot", "Leighton Earl", "Matthias Mailänder", "Oleg", "Ralf Hersel", "Taylor Braun-Jones", "Thomas Haider", "Timo Kankare", "Vincent Cheng" ]) aboutdialog.set_translator_credits(_("translator-credits")) aboutdialog.set_artists(["Reda Lazri"]) aboutdialog.connect("response", lambda w, r: aboutdialog.destroy()) aboutdialog.set_modal(True) aboutdialog.set_transient_for(self._window) aboutdialog.show()
def _notify_summary(self, new_mails, all_mails): summary = "" body = "" mails = self._prepend_new_mails(new_mails, all_mails) if len(self._notifications) == 0: self._notifications['0'] = self._get_notification(" ", None, None) # empty string will emit a gtk warning ubound = len(mails) if len(mails) <= self._max_mails else self._max_mails for i in range(ubound): if self._is_gnome: body += "%s:\n<i>%s</i>\n\n" % (self._get_sender(mails[i]), mails[i].subject) else: body += "%s - %s\n" % (ellipsize(self._get_sender(mails[i]), 20), ellipsize(mails[i].subject, 20)) if len(mails) > self._max_mails: if self._is_gnome: body += "<i>%s</i>" % _("(and {0} more)").format(str(len(mails) - self._max_mails)) else: body += _("(and {0} more)").format(str(len(mails) - self._max_mails)) if len(mails) > 1: # multiple new emails summary = _("{0} new mails").format(str(len(mails))) else: summary = _("New mail") self._notifications['0'].update(summary, body, "mail-unread") self._notifications['0'].show()
def __init__(self, parent, acc): self._acc = acc builder = Gtk.Builder() builder.set_translation_domain(PACKAGE_NAME) builder.add_from_file(get_data_file("account_dialog.ui")) builder.connect_signals({ \ "account_type_changed" : self._on_cmb_account_type_changed, \ "entry_changed" : self._on_entry_changed, \ "btn_cancel_clicked" : self._on_btn_cancel_clicked, \ "btn_save_clicked" : self._on_btn_save_clicked \ }) self._window = builder.get_object("account_dialog") self._window.set_transient_for(parent) self._cmb_account_type = builder.get_object("cmb_account_type") self._label_account_name = builder.get_object("label_account_name") self._entry_account_name = builder.get_object("entry_account_name") self._entry_account_user = builder.get_object("entry_account_user") self._entry_account_password = builder.get_object("entry_account_password") self._label_account_server = builder.get_object("label_account_server") self._entry_account_server = builder.get_object("entry_account_server") self._label_account_port = builder.get_object("label_account_port") self._entry_account_port = builder.get_object("entry_account_port") self._label_account_folders = builder.get_object("label_account_folders") self._entry_account_folders = builder.get_object("entry_account_folders") self._chk_account_push = builder.get_object("chk_account_push") self._chk_account_ssl = builder.get_object("chk_account_ssl") self._button_save = builder.get_object("button_save") self._entry_account_port.set_placeholder_text(_("optional")) self._entry_account_folders.set_placeholder_text(_("optional"))
def _on_btn_info_clicked(self, widget): aboutdialog = Gtk.AboutDialog() aboutdialog.set_title(_("About %s") % PACKAGE_NAME.title()) aboutdialog.set_version(APP_VERSION) aboutdialog.set_program_name(PACKAGE_NAME.title()) aboutdialog.set_comments(_("An extensible mail notification daemon.")) aboutdialog.set_copyright(_("Copyright (c) 2011 - 2019 Patrick Ulbrich and contributors.")) aboutdialog.set_logo_icon_name("mailnag") aboutdialog.set_website("https://github.com/pulb/mailnag") aboutdialog.set_website_label(_("Homepage")) aboutdialog.set_license_type(Gtk.License.GPL_2_0) aboutdialog.set_authors([ "Patrick Ulbrich (maintainer)", "Balló György", "Edwin Smulders", "Freeroot", "James Powell", "Leighton Earl", "Matthias Mailänder", "Oleg", "Ralf Hersel", "Taylor Braun-Jones", "Thomas Haider", "Timo Kankare", "Vincent Cheng" ]) aboutdialog.set_translator_credits(_("translator-credits")) aboutdialog.set_artists([ "Reda Lazri" ]) aboutdialog.connect("response", lambda w, r: aboutdialog.destroy()) aboutdialog.set_modal(True) aboutdialog.set_transient_for(self._window) aboutdialog.show()
def _fill_account_type_cmb(self): # fill acount type cmb for p in PROVIDER_CONFIGS: self._cmb_account_type.append_text(p[0]) self._cmb_account_type.append_text(_("Other (IMAP)")) self._cmb_account_type.append_text(_("Other (POP3)")) # select account type if len(self._acc.server) == 0: # default to Gmail when creating new accounts self._cmb_account_type.set_active(IDX_GMAIL) # triggers _on_cmb_account_type_changed() else: i = 0 idx = -1 for p in PROVIDER_CONFIGS: if (('%s (%s)' % (self._acc.user, p[0])) == self._acc.name) and \ p[1] == self._acc.server and \ p[2] == self._acc.port: idx = i break i+=1 if idx >= 0: self._cmb_account_type.set_active(idx) # triggers _on_cmb_account_type_changed() else: self._cmb_account_type.set_active(IDX_IMAP if self._acc.imap else IDX_POP3) # triggers _on_cmb_account_type_changed() # Don't allow changing the account type if the loaded account has folders. self._cmb_account_type.set_sensitive(len(self._acc.folders) == 0)
def _notify_count(self, count): if len(self._notifications) == 0: self._notifications['0'] = self._get_notification(" ", None, None) # empty string will emit a gtk warning if count > 1: # multiple new emails summary = _("{0} new mails").format(str(count)) else: summary = _("New mail") self._notifications['0'].update(summary, None, "mail-unread") self._notifications['0'].show()
def _fill_account_type_cmb(self): # fill acount type cmb for p in PROVIDER_CONFIGS: self._cmb_account_type.append_text(p[0]) self._cmb_account_type.append_text(_("IMAP (Custom)")) self._cmb_account_type.append_text(_("POP3 (Custom)")) self._cmb_account_type.append_text(_("MBox (Custom)")) self._cmb_account_type.append_text(_("Maildir (Custom)")) self._cmb_account_type.append_text(_("GMail RSS (No IMAP)")) config = self._acc.get_config() # select account type if self._acc.mailbox_type == '': # default to Gmail when creating new accounts idx = IDX_GMAIL else: idx = -1 if 'user' in config and 'server' in config and 'port' in config: user = config['user'] server = config['server'] port = config['port'] for i, p in enumerate(PROVIDER_CONFIGS): if (('%s (%s)' % (user, p[0])) == self._acc.name) and \ p[1] == server and p[2] == port: idx = i break if idx < 0: if self._acc.mailbox_type == 'imap': idx = IDX_IMAP elif self._acc.mailbox_type == 'pop3': idx = IDX_POP3 elif self._acc.mailbox_type == 'mbox': idx = IDX_MBOX elif self._acc.mailbox_type == 'maildir': idx = IDX_MAILDIR elif self._acc.mailbox_type == 'gmail_rss': idx = IDX_GMAIL_RSS else: # This is actually error case, but recovering to IMAP idx = IDX_IMAP self._cmb_account_type.set_active( idx) # triggers _on_cmb_account_type_changed() # Don't allow changing the account type if the loaded account has folders. if 'folders' in config: is_type_change_allowed = len(config['folders']) == 0 else: is_type_change_allowed = True self._cmb_account_type.set_sensitive(is_type_change_allowed)
def __init__(self, parent, acc): self._acc = acc builder = Gtk.Builder() builder.set_translation_domain(PACKAGE_NAME) builder.add_from_file(get_data_file("account_dialog.ui")) builder.connect_signals({ \ "account_type_changed" : self._on_cmb_account_type_changed, \ "entry_changed" : self._on_entry_changed, \ "expander_folders_activate" : self._on_expander_folders_activate, \ "btn_cancel_clicked" : self._on_btn_cancel_clicked, \ "btn_save_clicked" : self._on_btn_save_clicked \ }) self._window = builder.get_object("account_dialog") self._window.set_transient_for(parent) self._cmb_account_type = builder.get_object("cmb_account_type") self._label_account_name = builder.get_object("label_account_name") self._entry_account_name = builder.get_object("entry_account_name") self._entry_account_user = builder.get_object("entry_account_user") self._entry_account_password = builder.get_object("entry_account_password") self._label_account_server = builder.get_object("label_account_server") self._entry_account_server = builder.get_object("entry_account_server") self._label_account_port = builder.get_object("label_account_port") self._entry_account_port = builder.get_object("entry_account_port") self._expander_folders = builder.get_object("expander_folders") self._overlay = builder.get_object("overlay") self._treeview_folders = builder.get_object("treeview_folders") self._liststore_folders = builder.get_object("liststore_folders") self._chk_account_push = builder.get_object("chk_account_push") self._chk_account_ssl = builder.get_object("chk_account_ssl") self._button_save = builder.get_object("button_save") self._error_label = None self._folders_received = False self._selected_folder_count = 0 self._entry_account_port.set_placeholder_text(_("optional")) renderer_folders_enabled = Gtk.CellRendererToggle() renderer_folders_enabled.connect("toggled", self._on_folder_toggled) column_folders_enabled = Gtk.TreeViewColumn(_('Enabled'), renderer_folders_enabled) column_folders_enabled.add_attribute(renderer_folders_enabled, "active", 0) column_folders_enabled.set_alignment(0.5) self._treeview_folders.append_column(column_folders_enabled) renderer_folders_name = Gtk.CellRendererText() column_folders_name = Gtk.TreeViewColumn(_('Name'), renderer_folders_name, text = 1) self._treeview_folders.append_column(column_folders_name)
def _get_header(self, msg_dict): try: content = self._get_header_field(msg_dict, 'From') sender = self._format_header_field('sender', content) except: sender = ('', '') try: content = self._get_header_field(msg_dict, 'Subject') except: content = _('No subject') try: subject = self._format_header_field('subject', content) except: subject = '' try: content = self._get_header_field(msg_dict, 'Date') datetime = self._format_header_field('date', content) except: logging.warning('Email date set to zero.') datetime = 0 try: msgid = self._get_header_field(msg_dict, 'Message-ID') except: msgid = '' return (sender, subject, datetime, msgid)
def get_config_ui(self): box = Gtk.Box() box.set_spacing(12) box.set_orientation(Gtk.Orientation.VERTICAL) #box.set_size_request(100, -1) desc = _('Mailnag will ignore mails containing at least one of \nthe following words in subject or sender.') label = Gtk.Label(desc) label.set_line_wrap(True) #label.set_size_request(100, -1); box.pack_start(label, False, False, 0) scrollwin = Gtk.ScrolledWindow() scrollwin.set_shadow_type(Gtk.ShadowType.IN) scrollwin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scrollwin.set_size_request(-1, 60) txtbuffer = Gtk.TextBuffer() txtview = Gtk.TextView() txtview.set_buffer(txtbuffer) txtview.set_wrap_mode(Gtk.WrapMode.WORD) scrollwin.add(txtview) box.pack_start(scrollwin, True, True, 0) return box
def finished_func(): spinner.stop() spinner.destroy() if exception != None: self._error_label = Gtk.Label() self._error_label.set_justify(Gtk.Justification.CENTER) self._error_label.set_halign(Gtk.Align.CENTER) self._error_label.set_valign(Gtk.Align.CENTER) self._error_label.set_markup('<span foreground="red"><b>%s</b></span>' % _('Connection failed.')) self._overlay.add_overlay(self._error_label) self._overlay.show_all() else: for f in folders: enabled = False if f in self._acc.folders: enabled = True self._selected_folder_count += 1 row = [enabled, f] self._liststore_folders.append(row) # Enable the push checkbox in case a remote folder wasn't found # and the folder count is now <2. # (e.g. folders have been renamed/removed on the server, the user has entered a # diffent username/password in this dialog, ...) self._chk_account_push.set_sensitive(self._selected_folder_count < 2) self._folders_received = True
def _fill_account_type_cmb(self): # fill acount type cmb for p in PROVIDER_CONFIGS: self._cmb_account_type.append_text(p[0]) self._cmb_account_type.append_text(_("IMAP (Custom)")) self._cmb_account_type.append_text(_("POP3 (Custom)")) self._cmb_account_type.append_text(_("MBox (Custom)")) self._cmb_account_type.append_text(_("Maildir (Custom)")) config = self._acc.get_config() # select account type if self._acc.mailbox_type == '': # default to Gmail when creating new accounts idx = IDX_GMAIL else: idx = -1 if 'user' in config and 'server' in config and 'port' in config: user = config['user'] server = config['server'] port = config['port'] for i, p in enumerate(PROVIDER_CONFIGS): if (('%s (%s)' % (user, p[0])) == self._acc.name) and \ p[1] == server and p[2] == port: idx = i break if idx < 0: if self._acc.mailbox_type == 'imap': idx = IDX_IMAP elif self._acc.mailbox_type == 'pop3': idx = IDX_POP3 elif self._acc.mailbox_type == 'mbox': idx = IDX_MBOX elif self._acc.mailbox_type == 'maildir': idx = IDX_MAILDIR else: # This is actually error case, but recovering to IMAP idx = IDX_IMAP self._cmb_account_type.set_active(idx) # triggers _on_cmb_account_type_changed() # Don't allow changing the account type if the loaded account has folders. if 'folders' in config: is_type_change_allowed = len(config['folders']) == 0 else: is_type_change_allowed = True self._cmb_account_type.set_sensitive(is_type_change_allowed)
def __init__(self, parent, plugin): self._plugin = plugin flags = Gtk.DialogFlags.MODAL # | Gtk.DialogFlags.USE_HEADER_BAR self._window = Gtk.Dialog(_('Plugin Configuration'), parent, flags, \ (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK)) self._box = self._window.get_content_area() self._box.set_border_width(6) self._box.set_spacing(6)
def get_config_ui(self): box = Gtk.Box() box.set_spacing(12) box.set_orientation(Gtk.Orientation.VERTICAL) label = Gtk.Label() label.set_markup('<b>%s</b>' % _('Notification mode:')) label.set_alignment(0.0, 0.0) box.pack_start(label, False, False, 0) inner_box = Gtk.Box() inner_box.set_spacing(6) inner_box.set_orientation(Gtk.Orientation.VERTICAL) cb_count = Gtk.RadioButton(label = _('Count of new mails')) inner_box.pack_start(cb_count, False, False, 0) cb_summary = Gtk.RadioButton(label = _('Summary of new mails'), group = cb_count) inner_box.pack_start(cb_summary, False, False, 0) cb_single = Gtk.RadioButton(label = _('One notification per new mail'), group = cb_count) inner_box.pack_start(cb_single, False, False, 0) alignment = Gtk.Alignment() alignment.set_padding(0, 6, 18, 0) alignment.add(inner_box) box.pack_start(alignment, False, False, 0) label = Gtk.Label() label.set_markup('<b>%s</b>' % _('Maximum number of visible mails:')) label.set_alignment(0.0, 0.0) box.pack_start(label, False, False, 0) spinner = Gtk.SpinButton.new_with_range(1.0, MAX_VISIBLE_MAILS_LIMIT, 1.0) alignment = Gtk.Alignment() alignment.set_padding(0, 0, 18, 0) alignment.add(spinner) box.pack_start(alignment, False, False, 0) return box
def __init__(self, parent, plugin): self._plugin = plugin self._window = Gtk.Dialog(title = _('Plugin Configuration'), parent = parent, use_header_bar = True, \ buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK)) self._window.set_default_response(Gtk.ResponseType.OK) self._window.set_default_size(480, 0) self._box = self._window.get_content_area() self._box.set_border_width(12) self._box.set_spacing(12)
def get_config_ui(self): box = Gtk.Box() box.set_spacing(12) box.set_orientation(Gtk.Orientation.HORIZONTAL) label = Gtk.Label(_('Maximum number of visible mails:')) spinner = Gtk.SpinButton.new_with_range(1.0, MAX_VISIBLE_MAILS_LIMIT, 1.0) box.pack_start(label, False, False, 0) box.pack_start(spinner, False, False, 0) return box
def get_config_ui(self): box = Gtk.Box() box.set_spacing(12) box.set_orientation(Gtk.Orientation.VERTICAL) #box.set_size_request(100, -1) markup_str = "<i><%s> <%s> <%s></i>" % (_('account'), _('sender'), _('subject')) desc = _( "The following script will be executed whenever new mails arrive.\n" "Mailnag passes the total count of new mails to this script,\n" "followed by %s sequences.") % markup_str label = Gtk.Label() label.set_line_wrap(True) label.set_markup(desc) #label.set_size_request(100, -1); box.pack_start(label, False, False, 0) filechooser = Gtk.FileChooserButton() box.pack_start(filechooser, True, True, 0) return box
def get_config_ui(self): box = Gtk.Box() box.set_spacing(12) box.set_orientation(Gtk.Orientation.VERTICAL) #box.set_size_request(100, -1) markup_str = "<i><%s> <%s></i>" % (_('sender'), _('subject')) desc = _( "The following script will be executed whenever new mails arrive.\n" "Mailnag passes the total count of new mails to this script,\n" "followed by %s pairs." % markup_str) label = Gtk.Label() label.set_line_wrap(True) label.set_markup(desc) #label.set_size_request(100, -1); box.pack_start(label, False, False, 0) filechooser = Gtk.FileChooserButton() box.pack_start(filechooser, True, True, 0) return box
def get_config_ui(self): radio_mapping = [ (NOTIFICATION_MODE_COUNT, Gtk.RadioButton(label=_('Count of new mails'))), (NOTIFICATION_MODE_SHORT_SUMMARY, Gtk.RadioButton(label=_('Short summary of new mails'))), (NOTIFICATION_MODE_SUMMARY, Gtk.RadioButton(label=_('Detailed summary of new mails'))), (NOTIFICATION_MODE_SINGLE, Gtk.RadioButton(label=_('One notification per new mail'))) ] box = Gtk.Box() box.set_spacing(12) box.set_orientation(Gtk.Orientation.VERTICAL) label = Gtk.Label() label.set_markup('<b>%s</b>' % _('Notification mode:')) label.set_alignment(0.0, 0.0) box.pack_start(label, False, False, 0) inner_box = Gtk.Box() inner_box.set_spacing(6) inner_box.set_orientation(Gtk.Orientation.VERTICAL) last_radio = None for m, r in radio_mapping: if last_radio != None: r.join_group(last_radio) inner_box.pack_start(r, False, False, 0) last_radio = r alignment = Gtk.Alignment() alignment.set_padding(0, 6, 18, 0) alignment.add(inner_box) box.pack_start(alignment, False, False, 0) box._radio_mapping = radio_mapping return box
def _notify_single(self, mails): # In single notification mode new mails are # added to the *bottom* of the notification list. mails = sort_mails(mails, sort_desc = False) for mail in mails: n = self._get_notification(self._get_sender(mail), mail.subject, "mail-unread") notification_id = str(id(n)) if self._is_gnome: n.add_action("mark-as-read", _("Mark as read"), self._notification_action_handler, (mail, notification_id)) n.show() self._notifications[notification_id] = n
def _notify_short_summary(self, new_mails, all_mails): summary = "" body = "" lst = [] mails = self._prepend_new_mails(new_mails, all_mails) mail_count = len(mails) if len(self._notifications) == 0: self._notifications['0'] = self._get_notification( " ", None, None) # empty string will emit a gtk warning i = 0 n = 0 while (n < 3) and (i < mail_count): s = self._get_sender(mails[i]) if s not in lst: lst.append(s) n += 1 i += 1 if self._is_gnome: senders = "<i>%s</i>" % ", ".join(lst) else: senders = ", ".join(lst) if mail_count > 1: summary = _("{0} new mails").format(str(mail_count)) if (mail_count - i) > 1: body = _("from {0} and others.").format(senders) else: body = _("from {0}.").format(senders) else: summary = _("New mail") body = _("from {0}.").format(senders) self._notifications['0'].update(summary, body, "mail-unread") self._notifications['0'].show()
def _fill_account_type_cmb(self): # fill acount type cmb for p in PROVIDER_CONFIGS: self._cmb_account_type.append_text(p[0]) self._cmb_account_type.append_text(_("Other (IMAP)")) self._cmb_account_type.append_text(_("Other (POP3)")) # select account type if len(self._acc.server) == 0: # default to Gmail when creating new accounts self._cmb_account_type.set_active(IDX_GMAIL) else: i = 0 idx = -1 for p in PROVIDER_CONFIGS: if p[1] == self._acc.server: idx = i break i+=1 if idx >= 0: self._cmb_account_type.set_active(idx) else: self._cmb_account_type.set_active(IDX_IMAP if self._acc.imap else IDX_POP3)
def get_config_ui(self): radio_mapping = [ (NOTIFICATION_MODE_COUNT, Gtk.RadioButton(label = _('Count of new mails'))), (NOTIFICATION_MODE_SHORT_SUMMARY, Gtk.RadioButton(label = _('Short summary of new mails'))), (NOTIFICATION_MODE_SUMMARY, Gtk.RadioButton(label = _('Detailed summary of new mails'))), (NOTIFICATION_MODE_SINGLE, Gtk.RadioButton(label = _('One notification per new mail'))) ] box = Gtk.Box() box.set_spacing(12) box.set_orientation(Gtk.Orientation.VERTICAL) label = Gtk.Label() label.set_markup('<b>%s</b>' % _('Notification mode:')) label.set_alignment(0.0, 0.0) box.pack_start(label, False, False, 0) inner_box = Gtk.Box() inner_box.set_spacing(6) inner_box.set_orientation(Gtk.Orientation.VERTICAL) last_radio = None for m, r in radio_mapping: if last_radio != None: r.join_group(last_radio) inner_box.pack_start(r, False, False, 0) last_radio = r alignment = Gtk.Alignment() alignment.set_padding(0, 6, 18, 0) alignment.add(inner_box) box.pack_start(alignment, False, False, 0) box._radio_mapping = radio_mapping return box
def __init__(self, enabled = False, name = _('Unnamed'), user = '', \ password = '', oauth2string = '', server = '', port = '', ssl = True, imap = True, idle = True, folders = []): self.enabled = enabled # bool self.name = name self.user = user self.password = password self.oauth2string = oauth2string self.server = server self.port = port self.ssl = ssl # bool self.imap = imap # bool self.idle = idle # bool self.folders = folders self._conn = None
def _notify_short_summary(self, new_mails, all_mails): summary = "" body = "" lst = [] mails = self._prepend_new_mails(new_mails, all_mails) mail_count = len(mails) if len(self._notifications) == 0: self._notifications['0'] = self._get_notification(" ", None, None) # empty string will emit a gtk warning i = 0 n = 0 while (n < 3) and (i < mail_count): s = self._get_sender(mails[i]) if s not in lst: lst.append(s) n += 1 i += 1 if self._is_gnome: senders = "<i>%s</i>" % ", ".join(lst) else: senders = ", ".join(lst) if mail_count > 1: summary = _("{0} new mails").format(str(mail_count)) if (mail_count - i) > 1: body = _("from {0} and others.").format(senders) else: body = _("from {0}.").format(senders) else: summary = _("New mail") body = _("from {0}.").format(senders) self._notifications['0'].update(summary, body, "mail-unread") self._notifications['0'].show()
def _notify_summary(self, new_mails, all_mails): summary = "" body = "" # The mail list (all_mails) is sorted by date (mails with most recent # date on top). New mails with no date or older mails that come in # delayed won't be listed on top. So if a mail with no or an older date # arrives, it gives the impression that the top most mail (i.e. the mail # with the most recent date) is re-notified. # To fix that, simply put new mails on top explicitly. mails = new_mails + [m for m in all_mails if m not in new_mails] if len(self._notifications) == 0: self._notifications['0'] = self._get_notification(" ", None, None) # empty string will emit a gtk warning ubound = len(mails) if len(mails) <= self._max_mails else self._max_mails for i in range(ubound): if self._is_gnome: body += "%s:\n<i>%s</i>\n\n" % (self._get_sender(mails[i]), mails[i].subject) else: body += "%s - %s\n" % (ellipsize(self._get_sender(mails[i]), 20), ellipsize(mails[i].subject, 20)) if len(mails) > self._max_mails: if self._is_gnome: body += "<i>%s</i>" % _("(and {0} more)").format(str(len(mails) - self._max_mails)) else: body += _("(and {0} more)").format(str(len(mails) - self._max_mails)) if len(mails) > 1: # multiple new emails summary = _("{0} new mails").format(str(len(mails))) else: summary = _("New mail") self._notifications['0'].update(summary, body, "mail-unread") self._notifications['0'].show()
def _on_btn_remove_account_clicked(self, widget): acc, model, iter = self._get_selected_account() if iter != None: if self._show_confirmation_dialog(_('Delete this account:') + \ '\n\n' + acc.name): # select prev/next account p = model.get_path(iter) if not p.prev(): p.next() self._select_account_path(p) # remove from treeview model.remove(iter) # remove from account manager self._accountman.remove(acc)
def _notify_single(self, mails): # In single notification mode new mails are # added to the *bottom* of the notification list. mails.sort(key=lambda m: m.datetime, reverse=False) for mail in mails: n = self._get_notification( self._get_sender(mail) + " (%s)" % mail.account_name, mail.subject, "mail-unread") notification_id = str(id(n)) if self._is_gnome: n.add_action("mark-as-read", _("Mark as read"), self._notification_action_handler, (mail, notification_id)) n.show() self._notifications[notification_id] = n
def _get_header(self, msg_dict): # Get sender sender = ('', '') try: content = self._get_header_field(msg_dict, 'From') # get the two parts of the sender addr = email.utils.parseaddr(content) if len(addr) != 2: logging.warning('Malformed sender field in message.') else: sender_real = self._convert(addr[0]) sender_addr = self._convert(addr[1]) sender = (sender_real, sender_addr) except: pass # Get subject try: content = self._get_header_field(msg_dict, 'Subject') subject = self._convert(content) except: subject = _('No subject') # Get date try: content = self._get_header_field(msg_dict, 'Date') # make a 10-tupel (UTC) parsed_date = email.utils.parsedate_tz(content) # convert 10-tupel to seconds incl. timezone shift datetime = email.utils.mktime_tz(parsed_date) except: logging.warning('Email date set to zero.') datetime = 0 # Get message id try: msgid = self._get_header_field(msg_dict, 'Message-ID') except: msgid = '' return (sender, subject, datetime, msgid)
def _notify_single(self, new_mails, all_mails): # Remove notifications for messages not in all_mails: for k, n in list(self._notifications.items()): if hasattr(n, 'mail') and not (n.mail in all_mails): # The user may have closed the notification: try_close(n) del self._notifications[k] # In single notification mode new mails are # added to the *bottom* of the notification list. new_mails.sort(key = lambda m: m.datetime, reverse = False) for mail in new_mails: n = self._get_notification(self._get_sender(mail), mail.subject, "mail-unread") # Remember the associated message, so we know when to remove the notification: n.mail = mail notification_id = str(id(n)) if self._is_gnome: n.add_action("mark-as-read", _("Mark as read"), self._notification_action_handler, (mail, notification_id)) n.show() self._notifications[notification_id] = n
def get_manifest(self): return (_("LibNotify Notifications"), _("Shows a popup when new mails arrive."), "1.1.1", "Patrick Ulbrich <*****@*****.**>", False)
def get_manifest(self): return (_("User Script"), _("Runs an user defined script on mail arrival."), "1.1", "Patrick Ulbrich <*****@*****.**>", False)
def get_manifest(self): return (_("User Script"), _("Runs an user defined script on mail arrival."), "1.2", "Patrick Ulbrich <*****@*****.**>", False)
def __init__(self, app): builder = Gtk.Builder() builder.set_translation_domain(PACKAGE_NAME) builder.add_from_file(get_data_file("config_window.ui")) builder.connect_signals({ \ "config_window_deleted" : self._on_config_window_deleted, \ "btn_info_clicked" : self._on_btn_info_clicked, \ "btn_add_account_clicked" : self._on_btn_add_account_clicked, \ "btn_edit_account_clicked" : self._on_btn_edit_account_clicked, \ "btn_remove_account_clicked" : self._on_btn_remove_account_clicked, \ "treeview_accounts_row_activated" : self._on_treeview_accounts_row_activated, \ "liststore_accounts_row_deleted" : self._on_liststore_accounts_row_deleted, \ "liststore_accounts_row_inserted" : self._on_liststore_accounts_row_inserted, \ "btn_edit_plugin_clicked" : self._on_btn_edit_plugin_clicked, \ "treeview_plugins_row_activated" : self._on_treeview_plugins_row_activated, \ "treeview_plugins_cursor_changed" : self._on_treeview_plugins_cursor_changed, \ }) self._window = builder.get_object("config_window") self._window.set_icon_name("mailnag") self._window.set_application(app) self._cfg = read_cfg() self._daemon_enabled = False self._switch_daemon_enabled = builder.get_object( "switch_daemon_enabled") # # accounts page # self._accountman = AccountManager( CredentialStore.from_string( self._cfg.get('core', 'credentialstore'))) self._treeview_accounts = builder.get_object("treeview_accounts") self._liststore_accounts = builder.get_object("liststore_accounts") self._button_edit_account = builder.get_object("btn_edit_account") self._button_remove_account = builder.get_object("btn_remove_account") self._button_edit_account.set_sensitive(False) self._button_remove_account.set_sensitive(False) renderer_acc_enabled = Gtk.CellRendererToggle() renderer_acc_enabled.connect("toggled", self._on_account_toggled) column_acc_enabled = Gtk.TreeViewColumn(_('Enabled'), renderer_acc_enabled) column_acc_enabled.add_attribute(renderer_acc_enabled, "active", 1) column_acc_enabled.set_alignment(0.5) self._treeview_accounts.append_column(column_acc_enabled) renderer_acc_name = Gtk.CellRendererText() column_acc_name = Gtk.TreeViewColumn(_('Name'), renderer_acc_name, text=2) self._treeview_accounts.append_column(column_acc_name) # # plugins page # self._treeview_plugins = builder.get_object("treeview_plugins") self._liststore_plugins = builder.get_object("liststore_plugins") self._button_edit_plugin = builder.get_object("btn_edit_plugin") self._button_edit_plugin.set_sensitive(False) def renderer_plugin_enabled_func(column, cell_renderer, model, iter, data): plugin = model.get_value(iter, 0) name, desc, ver, author, mandatory = plugin.get_manifest() cell_renderer.set_sensitive(not mandatory) renderer_plugin_enabled = Gtk.CellRendererToggle() renderer_plugin_enabled.connect("toggled", self._on_plugin_toggled) column_plugin_enabled = Gtk.TreeViewColumn(_('Enabled'), renderer_plugin_enabled) column_plugin_enabled.add_attribute(renderer_plugin_enabled, "active", 1) column_plugin_enabled.set_alignment(0.5) column_plugin_enabled.set_cell_data_func(renderer_plugin_enabled, renderer_plugin_enabled_func) self._treeview_plugins.append_column(column_plugin_enabled) renderer_plugin_name = Gtk.CellRendererText() column_plugin_name = Gtk.TreeViewColumn(_('Name'), renderer_plugin_name, markup=2) self._treeview_plugins.append_column(column_plugin_name) # load config self._load_config() self._window.show_all()
def get_manifest(self): return (_("Ubuntu Unity"), _("Shows new mails in Ubuntu's Messaging menu."), PLUGIN_VERSION, "Patrick Ulbrich <*****@*****.**>", False)
def get_manifest(self): return (_("DBus Service"), _("Exposes Mailnag's functionality via a DBus service."), "1.1", "Patrick Ulbrich <*****@*****.**>", True)
def get_manifest(self): return (_("Spam Filter"), _("Filters out unwanted mails."), "1.1", "Patrick Ulbrich <*****@*****.**>", False)
def get_manifest(self): return (_("MessagingMenu"), _("Shows new mails in the MessagingMenu indicator."), PLUGIN_VERSION, "Patrick Ulbrich <*****@*****.**>", False)
def get_manifest(self): return (_("Sound Notifications"), _("Plays a sound when new mails arrive."), "1.1", "Patrick Ulbrich <*****@*****.**>", False)
def __init__(self): builder = Gtk.Builder() builder.set_translation_domain(PACKAGE_NAME) builder.add_from_file(get_data_file("config_window.ui")) builder.connect_signals({ \ "config_window_deleted" : self._on_config_window_deleted, \ "btn_page_toggled" : self._on_btn_page_toggled, \ "btn_add_account_clicked" : self._on_btn_add_account_clicked, \ "btn_edit_account_clicked" : self._on_btn_edit_account_clicked, \ "btn_remove_account_clicked" : self._on_btn_remove_account_clicked, \ "treeview_accounts_row_activated" : self._on_treeview_accounts_row_activated, \ "liststore_accounts_row_deleted" : self._on_liststore_accounts_row_deleted, \ "liststore_accounts_row_inserted" : self._on_liststore_accounts_row_inserted, \ "btn_edit_plugin_clicked" : self._on_btn_edit_plugin_clicked, \ "treeview_plugins_row_activated" : self._on_treeview_plugins_row_activated, \ "treeview_plugins_cursor_changed" : self._on_treeview_plugins_cursor_changed, \ }) # Add icons in alternative data paths (e.g. ./data/icons) # to the icon search path in case Mailnag is launched # from a local directory (without installing). icon_theme = Gtk.IconTheme.get_default() for path in get_data_paths(): icon_theme.append_search_path(os.path.join(path, "icons")) self._window = builder.get_object("config_window") self._window.set_icon_name("mailnag") self._load_stylesheet('config_window.css') self._cfg = read_cfg() self.daemon_enabled = False # # toggle buttons / notebook # self._notebook = builder.get_object("notebook") self._box_navigation = builder.get_object("box_navigation") self._box_navigation.get_children()[0].set_active(True) # # general page # # The dimension of the png is expected to be 180x180 px pb = GdkPixbuf.Pixbuf.new_from_file(get_data_file("mailnag.png")) pb = pb.new_subpixbuf(0, 10, 180, 146) # crop whitespace at the bottom self._image_logo = builder.get_object("image_logo") self._image_logo.set_from_pixbuf(pb) self._label_app_desc = builder.get_object("label_app_desc") self._label_app_desc.set_markup("<span font=\"24\"><b>Mailnag</b></span>\nVersion %s" % str(APP_VERSION)) self._switch_daemon_enabled = builder.get_object("switch_daemon_enabled") # # accounts page # self._accountman = AccountManager(CredentialStore.from_string(self._cfg.get('core', 'credentialstore'))) self._treeview_accounts = builder.get_object("treeview_accounts") self._liststore_accounts = builder.get_object("liststore_accounts") self._button_edit_account = builder.get_object("btn_edit_account") self._button_remove_account = builder.get_object("btn_remove_account") self._button_edit_account.set_sensitive(False) self._button_remove_account.set_sensitive(False) renderer_acc_enabled = Gtk.CellRendererToggle() renderer_acc_enabled.connect("toggled", self._on_account_toggled) column_acc_enabled = Gtk.TreeViewColumn(_('Enabled'), renderer_acc_enabled) column_acc_enabled.add_attribute(renderer_acc_enabled, "active", 1) column_acc_enabled.set_alignment(0.5) self._treeview_accounts.append_column(column_acc_enabled) renderer_acc_name = Gtk.CellRendererText() column_acc_name = Gtk.TreeViewColumn(_('Name'), renderer_acc_name, text = 2) self._treeview_accounts.append_column(column_acc_name) # # plugins page # self._treeview_plugins = builder.get_object("treeview_plugins") self._liststore_plugins = builder.get_object("liststore_plugins") self._button_edit_plugin = builder.get_object("btn_edit_plugin") self._button_edit_plugin.set_sensitive(False) def renderer_plugin_enabled_func(column, cell_renderer, model, iter, data): plugin = model.get_value(iter, 0) name, desc, ver, author, mandatory = plugin.get_manifest() cell_renderer.set_sensitive(not mandatory) renderer_plugin_enabled = Gtk.CellRendererToggle() renderer_plugin_enabled.connect("toggled", self._on_plugin_toggled) column_plugin_enabled = Gtk.TreeViewColumn(_('Enabled'), renderer_plugin_enabled) column_plugin_enabled.add_attribute(renderer_plugin_enabled, "active", 1) column_plugin_enabled.set_alignment(0.5) column_plugin_enabled.set_cell_data_func(renderer_plugin_enabled, renderer_plugin_enabled_func) self._treeview_plugins.append_column(column_plugin_enabled) renderer_plugin_name = Gtk.CellRendererText() column_plugin_name = Gtk.TreeViewColumn(_('Name'), renderer_plugin_name, markup = 2) self._treeview_plugins.append_column(column_plugin_name) # load config self._load_config() self._window.show()
def get_manifest(self): return (_("DBus Service"), _("Exposes Mailnag's functionality via a DBus service."), "1.2", "Patrick Ulbrich <*****@*****.**>", True)
def get_manifest(self): return (_("User Script Custom"), _("Runs an user defined script on mail arrival."), "2.0", "Patrick Ulbrich <*****@*****.**>")
def __init__(self, parent, acc): self._acc = acc builder = Gtk.Builder() builder.set_translation_domain(PACKAGE_NAME) builder.add_from_file(get_data_file("account_widget.ui")) builder.connect_signals({ \ "account_type_changed" : self._on_cmb_account_type_changed, \ "entry_changed" : self._on_entry_changed, \ "expander_folders_activate" : self._on_expander_folders_activate \ }) self._window = Gtk.Dialog(title = _('Mail Account'), parent = parent, use_header_bar = True, \ buttons = (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK)) self._window.set_default_response(Gtk.ResponseType.OK) self._window.set_default_size(400, 0) self._box = self._window.get_content_area() self._box.set_border_width(12) self._box.set_spacing(12) self._box.pack_start(builder.get_object("account_widget"), True, True, 0) self._cmb_account_type = builder.get_object("cmb_account_type") self._label_account_name = builder.get_object("label_account_name") self._entry_account_name = builder.get_object("entry_account_name") self._label_account_user = builder.get_object("label_account_user") self._entry_account_user = builder.get_object("entry_account_user") self._label_account_password = builder.get_object("label_account_password") self._entry_account_password = builder.get_object("entry_account_password") self._label_account_server = builder.get_object("label_account_server") self._entry_account_server = builder.get_object("entry_account_server") self._label_account_port = builder.get_object("label_account_port") self._entry_account_port = builder.get_object("entry_account_port") self._label_account_file_path = builder.get_object("label_account_file_path") self._chooser_account_file_path = builder.get_object("chooser_file_path") self._label_account_directory_path = builder.get_object("label_account_directory_path") self._chooser_account_directory_path = builder.get_object("chooser_directory_path") self._expander_folders = builder.get_object("expander_folders") self._overlay = builder.get_object("overlay") self._treeview_folders = builder.get_object("treeview_folders") self._liststore_folders = builder.get_object("liststore_folders") self._chk_account_push = builder.get_object("chk_account_push") self._chk_account_ssl = builder.get_object("chk_account_ssl") self._button_ok = self._window.get_widget_for_response(Gtk.ResponseType.OK) self._button_ok.set_sensitive(False) self._error_label = None self._folders_received = False self._selected_folder_count = 0 self._entry_account_port.set_placeholder_text(_("optional")) renderer_folders_enabled = Gtk.CellRendererToggle() renderer_folders_enabled.connect("toggled", self._on_folder_toggled) column_folders_enabled = Gtk.TreeViewColumn(_('Enabled'), renderer_folders_enabled) column_folders_enabled.add_attribute(renderer_folders_enabled, "active", 0) column_folders_enabled.set_alignment(0.5) self._treeview_folders.append_column(column_folders_enabled) renderer_folders_name = Gtk.CellRendererText() column_folders_name = Gtk.TreeViewColumn(_('Name'), renderer_folders_name, text = 1) column_folders_name.set_cell_data_func(renderer_folders_name, folder_cell_data) self._treeview_folders.append_column(column_folders_name)