Merge master

This commit is contained in:
Patrick Ulbrich
2016-09-10 19:36:52 +02:00
10 changed files with 439 additions and 50 deletions

View File

@@ -16,8 +16,10 @@ Code, docs and packaging contributors:
Amin Bandali <me@aminb.org>
Edwin Smulders
Hasan Yavuz Özderya
Heiko Adams
Leighton Earl <leighton.earl@gmx.com>
Matthias Mailänder
Oleg <cheshire-mouse@users.noreply.github.com>
Taylor Braun-Jones <taylor@braun-jones.org>
Thorsten Leemhuis <Thorsten_leemhuis@gmx.de>
Thomas Haider <t.haider@deprecate.de>
@@ -63,6 +65,7 @@ Manuel Xosé Lemos
Marcos Lans
Marti Bosch
Mattia Meneguzzo
Микола Ткач
Мирослав Николић
Oleg «Eleidan» Kulyk
Patrick Ulbrich

View File

@@ -23,8 +23,10 @@
# MA 02110-1301, USA.
#
import re
import poplib
import logging
import json
import Mailnag.common.imaplib2 as imaplib
from Mailnag.common.utils import splitstr
@@ -38,7 +40,7 @@ account_defaults = {
'ssl' : '1',
'imap' : '1',
'idle' : '1',
'folder' : ''
'folder' : '[]'
}
CREDENTIAL_KEY = 'Mailnag password for %s://%s@%s'
@@ -105,22 +107,14 @@ class Account:
# conn.close() # allowed in SELECTED state only
conn.logout()
separators = [ ' "/" ', ' "." ' ]
for d in data:
folder = ''
for s in separators:
if s in d:
folder = d.split(s)[-1]
break
if len(folder) == 0:
match = re.match('.+\s+("."|"?NIL"?)\s+"?([^"]+)"?$', d)
if match == None:
logging.warning("Folder format not supported.")
break
if (folder[0] == '"') and (folder[-1] == '"'):
folder = folder[1:-1]
lst.append(folder)
else:
folder = match.group(2)
lst.append(folder)
return lst
@@ -283,7 +277,11 @@ class AccountManager:
ssl = bool(int( self._get_account_cfg(cfg, section_name, 'ssl') ))
imap = bool(int( self._get_account_cfg(cfg, section_name, 'imap') ))
idle = bool(int( self._get_account_cfg(cfg, section_name, 'idle') ))
folders = splitstr(self._get_account_cfg(cfg, section_name, 'folder'), ',')
folders_str = self._get_account_cfg(cfg, section_name, 'folder')
if re.match(r'^\[.*\]$', folders_str):
folders = json.loads(folders_str)
else:
folders = splitstr(folders_str, ',')
if self._credentialstore != None:
protocol = 'imap' if imap else 'pop'
@@ -336,7 +334,7 @@ class AccountManager:
cfg.set(section_name, 'ssl', int(acc.ssl))
cfg.set(section_name, 'imap', int(acc.imap))
cfg.set(section_name, 'idle', int(acc.idle))
cfg.set(section_name, 'folder', ', '.join(acc.folders))
cfg.set(section_name, 'folder', json.dumps(acc.folders))
if self._credentialstore != None:
protocol = 'imap' if acc.imap else 'pop'

97
Mailnag/common/mutf7.py Normal file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
'''
This awesome piece of code is intented to encode and decode modified UTF-7
(the one that is used for IMAP folder names)
encode_mutf7(text) - to encode
decode_mutf7(text) - to decode
'''
__author__ = "https://github.com/cheshire-mouse"
__license__ = "WTFPL v. 2"
import base64
import re
ascii_codes = set(range(0x20,0x7f))
def __get_ascii(text):
pos = 0
for c in text:
code=ord(c)
if ord(c) not in ascii_codes :
break
pos += 1
return text[:pos].encode('ascii')
def __remove_ascii(text):
pos = 0
for c in text:
if ord(c) not in ascii_codes :
break
pos += 1
return text[pos:]
def __get_nonascii(text):
pos = 0
for c in text:
code=ord(c)
if ord(c) in ascii_codes :
break
pos += 1
return text[:pos]
def __remove_nonascii(text):
pos = 0
for c in text:
if ord(c) in ascii_codes :
break
pos += 1
return text[pos:]
def __encode_modified_utf7(text):
#modified base64 - good old base64 without padding characters (=)
result = base64.b64encode(text.encode('utf-16be')).rstrip('=')
result = result.replace('/',',')
result = '&' + result + '-'
return result
def encode_mutf7(text):
result = ""
text = text.replace('&','&-')
while len(text) > 0:
result += __get_ascii(text)
text = __remove_ascii(text)
if len(text) > 0:
result += __encode_modified_utf7(__get_nonascii(text))
text = __remove_nonascii(text)
return result
def __decode_modified_utf7(text):
if text == '&-':
return '&'
#remove leading & and trailing -
text_mb64 = text[1:-1]
text_b64 = text_mb64.replace(',','/')
#back to normal base64 with padding
while len(text_b64) % 4 != 0:
text_b64 += '='
text_u16 = base64.b64decode(text_b64)
result = text_u16.decode('utf-16be')
return result
def decode_mutf7(text):
rxp = re.compile('&[^&-]*-')
match = rxp.search(text)
while ( match ):
encoded_text = match.group(0)
decoded_text = __decode_modified_utf7(encoded_text)
text = rxp.sub(decoded_text,text, count=1)
match = rxp.search(text)
result = text
return result
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

View File

@@ -28,10 +28,34 @@ import sys
import time
import dbus
import logging
import logging.handlers
import inspect
from Mailnag.common.dist_cfg import PACKAGE_NAME, DBUS_BUS_NAME, DBUS_OBJ_PATH
LOG_FORMAT = '%(levelname)s (%(asctime)s): %(message)s'
LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
def init_logging(enable_stdout = True, enable_syslog = True, log_level = logging.DEBUG):
logging.basicConfig(
format = LOG_FORMAT,
datefmt = LOG_DATE_FORMAT,
level = log_level)
logger = logging.getLogger('')
if not enable_stdout:
stdout_handler = logger.handlers[0]
logger.removeHandler(stdout_handler)
if enable_syslog:
syslog_handler = logging.handlers.SysLogHandler(address='/dev/log')
syslog_handler.setLevel(log_level)
syslog_handler.setFormatter(logging.Formatter(LOG_FORMAT, LOG_DATE_FORMAT))
logger.addHandler(syslog_handler)
def get_data_paths():
# Add "./data" in workdir for running from builddir

View File

@@ -31,6 +31,7 @@ from Mailnag.common.dist_cfg import PACKAGE_NAME
from Mailnag.common.i18n import _
from Mailnag.common.utils import get_data_file, splitstr
from Mailnag.common.accounts import Account
from Mailnag.common import mutf7
IDX_GMAIL = 0
IDX_GMX = 1
@@ -179,7 +180,7 @@ class AccountDialog:
folders = []
for row in self._liststore_folders:
if row[0]:
folders.append(row[1])
folders.append(mutf7.encode_mutf7(row[1].decode('utf-8')))
return folders
@@ -283,7 +284,7 @@ class AccountDialog:
if f in self._acc.folders:
enabled = True
self._selected_folder_count += 1
row = [enabled, f]
row = [enabled, mutf7.decode_mutf7(f)]
self._liststore_folders.append(row)
# Enable the push checkbox in case a remote folder wasn't found

View File

@@ -3,7 +3,7 @@
#
# conntest.py
#
# Copyright 2014 Patrick Ulbrich <zulu99@gmx.net>
# Copyright 2014, 2016 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
@@ -24,7 +24,7 @@
import os
import dbus
PING_TEST_HOST = 'www.google.de'
PING_TEST_HOST = 'www.google.com'
NM_STATE_CONNECTED_GLOBAL = 70

View File

@@ -29,7 +29,7 @@ As of Ubuntu 13.04 (Raring), Mailnag is also available in the official repos.
Run `sudo apt-get install mailnag` in a terminal to install it.
### Debian
Mailnag is currently available in Debian unstable.
Mailnag is available in Debian stable and unstable.
Run `sudo apt-get install mailnag` in a terminal to install it.
### Fedora

30
mailnag
View File

@@ -31,7 +31,6 @@ from dbus.mainloop.glib import DBusGMainLoop
import threading
import argparse
import logging
import logging.handlers
import os
import signal
@@ -41,16 +40,14 @@ fix_cwd()
from Mailnag.common.config import cfg_exists
from Mailnag.common.dist_cfg import APP_VERSION
from Mailnag.common.utils import set_procname, shutdown_existing_instance
from Mailnag.common.utils import set_procname, init_logging, shutdown_existing_instance
from Mailnag.common.subproc import terminate_subprocesses
from Mailnag.common.exceptions import InvalidOperationException
from Mailnag.daemon.mailnagdaemon import MailnagDaemon
PROGNAME = 'mailnag'
LOG_LEVEL = logging.DEBUG
LOG_FORMAT = '%(levelname)s (%(asctime)s): %(message)s'
LOG_DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
def cleanup(daemon):
event = threading.Event()
@@ -81,27 +78,7 @@ def get_args():
version = '%s %s' % (PROGNAME, APP_VERSION))
return parser.parse_args()
def init_logging(enable_stdout = True):
logging.basicConfig(
format = LOG_FORMAT,
datefmt = LOG_DATE_FORMAT,
level = LOG_LEVEL)
logger = logging.getLogger('')
syslog_handler = logging.handlers.SysLogHandler(address='/dev/log')
syslog_handler.setLevel(LOG_LEVEL)
syslog_handler.setFormatter(logging.Formatter(LOG_FORMAT, LOG_DATE_FORMAT))
stdout_handler = logger.handlers[0]
logger.addHandler(syslog_handler)
if not enable_stdout:
logger.removeHandler(stdout_handler)
def sigterm_handler(mainloop):
if mainloop != None:
@@ -127,7 +104,8 @@ def main():
# Note: don't start logging before an existing Mailnag
# instance has been shut down completely (will corrupt logfile).
init_logging(not args.quiet)
init_logging(enable_stdout = (not args.quiet), \
enable_syslog = True, log_level = LOG_LEVEL)
try:
if not cfg_exists():

View File

@@ -27,9 +27,10 @@ gi.require_version('GLib', '2.0')
import os
import subprocess
import logging
from gi.repository import Gtk, Gio
from Mailnag.common.utils import fix_cwd
from Mailnag.common.utils import fix_cwd, init_logging
fix_cwd()
@@ -38,6 +39,8 @@ from Mailnag.common.utils import set_procname, shutdown_existing_instance, get_d
from Mailnag.common.dist_cfg import BIN_DIR, PACKAGE_NAME
from Mailnag.configuration.configwindow import ConfigWindow
LOG_LEVEL = logging.DEBUG
class App(Gtk.Application):
def __init__(self):
@@ -115,7 +118,8 @@ class App(Gtk.Application):
def main():
set_procname("mailnag-config")
init_logging(enable_stdout = True, enable_syslog = False, log_level = LOG_LEVEL)
app = App()
app.run(None)

284
po/ru.po Normal file
View File

@@ -0,0 +1,284 @@
# Mailnag russian tranlation
# This file is distributed under the same license as the mailnag package.
# Oleg <cheshire-mouse@users.noreply.github.com>, 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: mailnag\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-02-03 19:08+0100\n"
"PO-Revision-Date: 2016-08-17 2O:00+0300\n"
"Last-Translator: Oleg <cheshire-mouse@users.noreply.github.com>\n"
"Language: RU\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: Mailnag/plugins/userscriptplugin.py:62
msgid "User Script"
msgstr "Пользовательский скрипт"
#: Mailnag/plugins/userscriptplugin.py:63
msgid "Runs an user defined script on mail arrival."
msgstr "Запустить пользовательский скрипт при получении почты"
#: Mailnag/plugins/userscriptplugin.py:83
msgid "account"
msgstr "учетная запись"
#: Mailnag/plugins/userscriptplugin.py:83
msgid "sender"
msgstr "отправитель"
#: Mailnag/plugins/userscriptplugin.py:83
msgid "subject"
msgstr "тема"
#: Mailnag/plugins/userscriptplugin.py:84
#, python-format
msgid ""
"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."
msgstr ""
"Следующий скрипт будет выполнен при появлении новых сообщений.\n"
"Скрипту передаётся количество сообщений,\n"
"за которым следуют: %s"
#: Mailnag/plugins/unityplugin.py:98
msgid "Ubuntu Unity"
msgstr ""
#: Mailnag/plugins/unityplugin.py:99
msgid "Shows new mails in Ubuntu's Messaging menu."
msgstr "Отображает новые письма в меню сообщений Ubuntu."
#: Mailnag/plugins/unityplugin.py:118
msgid "Maximum number of visible mails:"
msgstr "Максимальное количество отображаемых писем:"
#: Mailnag/plugins/spamfilterplugin.py:69
msgid "Spam Filter"
msgstr "Спам фильтр"
#: Mailnag/plugins/spamfilterplugin.py:70
msgid "Filters out unwanted mails."
msgstr "Фильтрует нежелательные сообщения."
#: Mailnag/plugins/spamfilterplugin.py:90
msgid ""
"Mailnag will ignore mails containing at least one of \n"
"the following words in subject or sender."
msgstr ""
"Mailnag проигнорирует письмо, если имя отправителя\n"
"или тема содержит одно из следующих слов"
#: Mailnag/plugins/libnotifyplugin.py:100
msgid "LibNotify Notifications"
msgstr "Уведомления LibNotify"
#: Mailnag/plugins/libnotifyplugin.py:101
msgid "Shows a popup when new mails arrive."
msgstr "Отображение всплывающего уведомления при получении новых писем"
#: Mailnag/plugins/libnotifyplugin.py:117
msgid "Count of new mails"
msgstr "Количество новых писем"
#: Mailnag/plugins/libnotifyplugin.py:118
msgid "Short summary of new mails"
msgstr "Краткие сведения о письмах"
#: Mailnag/plugins/libnotifyplugin.py:119
msgid "Detailed summary of new mails"
msgstr "Подробные сведения о письмах"
#: Mailnag/plugins/libnotifyplugin.py:120
msgid "One notification per new mail"
msgstr "Одно уведомление на письмо"
#: Mailnag/plugins/libnotifyplugin.py:128
msgid "Notification mode:"
msgstr "Тип уведомлений:"
#: Mailnag/plugins/libnotifyplugin.py:215
#: Mailnag/plugins/libnotifyplugin.py:251
#: Mailnag/plugins/libnotifyplugin.py:279
#, python-brace-format
msgid "{0} new mails"
msgstr "сообщений: {0}"
#: Mailnag/plugins/libnotifyplugin.py:217
#, python-brace-format
msgid "from {0} and others."
msgstr "от {0} и других."
#: Mailnag/plugins/libnotifyplugin.py:219
#: Mailnag/plugins/libnotifyplugin.py:222
#, python-brace-format
msgid "from {0}."
msgstr "от {0}."
#: Mailnag/plugins/libnotifyplugin.py:221
#: Mailnag/plugins/libnotifyplugin.py:253
#: Mailnag/plugins/libnotifyplugin.py:281
msgid "New mail"
msgstr "Новое сообщение"
#: Mailnag/plugins/libnotifyplugin.py:246
#: Mailnag/plugins/libnotifyplugin.py:248
#, python-brace-format
msgid "(and {0} more)"
msgstr "(и еще {0})"
#: Mailnag/plugins/libnotifyplugin.py:268
msgid "Mark as read"
msgstr "Отметить как прочитанное"
#: Mailnag/plugins/soundplugin.py:65
msgid "Sound Notifications"
msgstr "Звуковые уведомления"
#: Mailnag/plugins/soundplugin.py:66
msgid "Plays a sound when new mails arrive."
msgstr "Проигрывает мелодию при появлении нового сообщения."
#: Mailnag/plugins/goaplugin.py:93
msgid "GNOME Online Accounts"
msgstr ""
#: Mailnag/plugins/goaplugin.py:94
msgid "GNOME Online Accounts Integration."
msgstr ""
#: Mailnag/plugins/dbusplugin.py:83
msgid "DBus Service"
msgstr "Служба DBus"
#: Mailnag/plugins/dbusplugin.py:84
msgid "Exposes Mailnag's functionality via a DBus service."
msgstr "Доступ к фунциям Mailnag через службу DBus."
#: Mailnag/daemon/mails.py:171
msgid "No subject"
msgstr "Без темы"
#: Mailnag/configuration/plugindialog.py:33
msgid "Plugin Configuration"
msgstr "Настройка плагина"
#: Mailnag/configuration/configwindow.py:109
#: Mailnag/configuration/configwindow.py:134
#: Mailnag/configuration/accountdialog.py:88
msgid "Enabled"
msgstr "Включено"
#: Mailnag/configuration/configwindow.py:115
#: Mailnag/configuration/configwindow.py:141
#: Mailnag/configuration/accountdialog.py:94
msgid "Name"
msgstr "Имя"
#: Mailnag/configuration/configwindow.py:344
msgid "Delete this account:"
msgstr "Удалить учетную запись:"
#: Mailnag/configuration/accountdialog.py:84
msgid "optional"
msgstr "необязательно"
#: Mailnag/configuration/accountdialog.py:177
msgid "Other (IMAP)"
msgstr "Другое (IMAP)"
#: Mailnag/configuration/accountdialog.py:178
msgid "Other (POP3)"
msgstr "Другое (POP3)"
#: Mailnag/configuration/accountdialog.py:271
msgid "Connection failed."
msgstr "Ошибка соединения."
#: data/account_dialog.ui.h:1
msgid "Mail Account"
msgstr "Учетная запись"
#: data/account_dialog.ui.h:2
msgid "Enable Push-IMAP"
msgstr "Включить Push-IMAP"
#: data/account_dialog.ui.h:3
msgid "Enable SSL encryption"
msgstr "Включить SSL шифрование"
#: data/account_dialog.ui.h:4
msgid "Accountname:"
msgstr "Имя учетной записи:"
#: data/account_dialog.ui.h:5
msgid "Account type:"
msgstr "Тип учетной записи:"
#: data/account_dialog.ui.h:6
msgid "User:"
msgstr "Пользователь:"
#: data/account_dialog.ui.h:7
msgid "Password:"
msgstr "Пароль:"
#: data/account_dialog.ui.h:8
msgid "Server:"
msgstr "Сервер:"
#: data/account_dialog.ui.h:9
msgid "Port:"
msgstr "Порт:"
#: data/account_dialog.ui.h:10
msgid "Folders (optional)"
msgstr "Папки (необзязательно)"
#: data/config_window.ui.h:1
msgid "Mailnag Configuration"
msgstr "Настройки Mailnag"
#: data/config_window.ui.h:2
msgid "General"
msgstr "Общее"
#: data/config_window.ui.h:3
msgid "Accounts"
msgstr "Учетные записи"
#: data/config_window.ui.h:4
msgid "Plugins"
msgstr "Плагины"
#: data/config_window.ui.h:5
msgid ""
"<a href=\"https://github.com/pulb/mailnag\">Mailnag</a> - An extensible mail "
"notification daemon.\n"
"Copyright (c) 2011 - 2016 Patrick Ulbrich\n"
"and contributors."
msgstr ""
"<a href=\"https://github.com/pulb/mailnag\">Mailnag</a> - служба уведомлений "
"о входящей почте.\n"
"Copyright (c) 2011 - 2016 Patrick Ulbrich\n"
"and contributors."
#: data/config_window.ui.h:8
msgid "Add Account"
msgstr "Добавить учетную запись"
#: data/config_window.ui.h:9
msgid "Remove Account"
msgstr "Удалить учетную запись"
#: data/config_window.ui.h:10
msgid "Edit Account"
msgstr "Редактировать учетную запись"
#: data/config_window.ui.h:11
msgid "Edit Plugin"
msgstr "Редактировать плагин"