diff --git a/fetchmail_bydate/__init__.py b/fetchmail_bydate/__init__.py new file mode 100644 index 000000000..3ceb4ebf2 --- /dev/null +++ b/fetchmail_bydate/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Innoviu srl (). +# Copyright (C) 2015 Agile Business Group http://www.agilebg.com +# @authors +# Roberto Onnis +# Alessio Gerace +# Lorenzo Battistini +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +############################################################################## + +from . import model diff --git a/fetchmail_bydate/__openerp__.py b/fetchmail_bydate/__openerp__.py new file mode 100644 index 000000000..e3b2cfa34 --- /dev/null +++ b/fetchmail_bydate/__openerp__.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Innoviu srl (). +# Copyright (C) 2015 Agile Business Group http://www.agilebg.com +# @authors +# Roberto Onnis +# Alessio Gerace +# Lorenzo Battistini +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +############################################################################## +{ + 'name': "Fetchmail by Date", + "version": "1.0", + 'category': 'Mailing', + 'summary': 'Fetchmail by date and unseen messages', + 'description': """ +This module allows to fetch new emails (using IMAP) using their date, +in addition to 'unseen' status. + +To enable this, you have to set a 'Last Download Date' in the fetchmail.server +After that, emails with an internal date greater than the saved one will be +downloaded. +""", + 'author': "Innoviu, Agile Business Group, " + "Odoo Community Association (OCA)", + 'website': 'http://www.innoviu.com', + 'license': 'AGPL-3', + 'depends': ['fetchmail', 'mail'], + "data": [ + 'view/fetchmail_view.xml', + ], + 'demo': [], + 'test': [], + 'installable': True, + 'auto_install': False, +} diff --git a/fetchmail_bydate/model/__init__.py b/fetchmail_bydate/model/__init__.py new file mode 100644 index 000000000..8cf9e9c84 --- /dev/null +++ b/fetchmail_bydate/model/__init__.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Innoviu srl (). +# Copyright (C) 2015 Agile Business Group http://www.agilebg.com +# @authors +# Roberto Onnis +# Alessio Gerace +# Lorenzo Battistini +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +############################################################################## + +from . import fetchmail diff --git a/fetchmail_bydate/model/fetchmail.py b/fetchmail_bydate/model/fetchmail.py new file mode 100644 index 000000000..a17c65dfb --- /dev/null +++ b/fetchmail_bydate/model/fetchmail.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Innoviu srl (). +# Copyright (C) 2015 Agile Business Group http://www.agilebg.com +# @authors +# Roberto Onnis +# Alessio Gerace +# Lorenzo Battistini +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +############################################################################## +from openerp.osv import fields, orm +import logging +import imaplib +from datetime import datetime +import time + + +_logger = logging.getLogger(__name__) + + +class FetchmailServer(orm.Model): + + _inherit = "fetchmail.server" + + _columns = { + 'last_internal_date': fields.datetime( + 'Last Download Date', + help="Remote emails with a date greater than this will be " + "downloaded. Only available with IMAP"), + } + + def _fetch_from_date_imap(self, cr, uid, + server, imap_server, + mail_thread, action_pool, + count, failed, + context=None): + messages = [] + date_uids = {} + last_date = False + last_internal_date = datetime.strptime( + server.last_internal_date, "%Y-%m-%d %H:%M:%S") + search_status, uids = imap_server.search( + None, + 'SINCE', '%s' % last_internal_date.strftime('%d-%b-%Y') + ) + new_uids = uids[0].split() + for new_uid in new_uids: + fetch_status, date = imap_server.fetch( + int(new_uid), + 'INTERNALDATE' + ) + internaldate = imaplib.Internaldate2tuple(date[0]) + internaldate_msg = datetime.fromtimestamp( + time.mktime(internaldate) + ) + if internaldate_msg > last_internal_date: + messages.append(new_uid) + date_uids[new_uid] = internaldate_msg + for num in messages: + # SEARCH command *always* returns at least the most + # recent message, even if it has already been synced + res_id = None + result, data = imap_server.fetch(num, '(RFC822)') + if data and data[0]: + try: + res_id = mail_thread.message_process( + cr, uid, + server.object_id.model, + data[0][1], + save_original=server.original, + strip_attachments=(not server.attach), + context=context) + except Exception: + _logger.exception( + 'Failed to process mail \ + from %s server %s.', + server.type, + server.name) + failed += 1 + if res_id and server.action_id: + action_pool.run( + cr, uid, [server.action_id.id], + { + 'active_id': res_id, + 'active_ids': [res_id], + 'active_model': context.get( + "thread_model", + server.object_id.model) + }, context=context) + imap_server.store(num, '+FLAGS', '\\Seen') + cr.commit() + count += 1 + last_date = not failed and date_uids[num] or False + return count, failed, last_date + + def fetch_mail(self, cr, uid, ids, context=None): + if context is None: + context = {} + context['fetchmail_cron_running'] = True + mail_thread = self.pool.get('mail.thread') + action_pool = self.pool.get('ir.actions.server') + for server in self.browse(cr, uid, ids, context=context): + if server.type == 'imap' and server.last_internal_date: + _logger.info( + 'start checking for new emails by date on %s server %s', + server.type, server.name) + context.update({'fetchmail_server_id': server.id, + 'server_type': server.type}) + count, failed = 0, 0 + last_date = False + imap_server = False + try: + imap_server = server.connect() + imap_server.select() + count, failed, last_date = self._fetch_from_date_imap( + cr, uid, server, imap_server, mail_thread, + action_pool, count, failed, context=context + ) + except Exception: + _logger.exception( + "General failure when trying to fetch mail \ + from %s server %s.", + server.type, + server.name + ) + finally: + if imap_server: + imap_server.close() + imap_server.logout() + if last_date: + _logger.info( + "Fetched %d email(s) on %s server %s; \ + %d succeeded, %d failed.", count, + server.type, server.name, + (count - failed), failed) + vals = {'last_internal_date': last_date} + server.write(vals) + return super(FetchmailServer, self).fetch_mail( + cr, uid, ids, context=context) diff --git a/fetchmail_bydate/view/fetchmail_view.xml b/fetchmail_bydate/view/fetchmail_view.xml new file mode 100644 index 000000000..6a027ace9 --- /dev/null +++ b/fetchmail_bydate/view/fetchmail_view.xml @@ -0,0 +1,18 @@ + + + + + + fetchmail.bydate.form + fetchmail.server + + + + + + + + + + +