You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
5.6 KiB

  1. # -*- coding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # Author: Matthieu Dietrich
  5. # Copyright 2015 Camptocamp SA
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as
  9. # published by the Free Software Foundation, either version 3 of the
  10. # License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. ##############################################################################
  21. import logging
  22. from osv import fields
  23. from osv import osv
  24. from dateutil import relativedelta
  25. from datetime import datetime
  26. from server_environment import serv_config
  27. _logger = logging.getLogger(__name__)
  28. class FetchmailServer(osv.osv):
  29. """Incoming POP/IMAP mail server account"""
  30. _inherit = 'fetchmail.server'
  31. def _get_cleanup_conf(self, cursor, uid, ids, name, args, context=None):
  32. """
  33. Return configuration
  34. """
  35. res = {}
  36. for fetchmail in self.browse(cursor, uid, ids):
  37. global_section_name = 'incoming_mail'
  38. # default vals
  39. config_vals = {'cleanup_days': 30,
  40. 'cleanup_folder': False}
  41. if serv_config.has_section(global_section_name):
  42. config_vals.update(serv_config.items(global_section_name))
  43. custom_section_name = '.'.join((global_section_name,
  44. fetchmail.name))
  45. if serv_config.has_section(custom_section_name):
  46. config_vals.update(serv_config.items(custom_section_name))
  47. if config_vals.get('cleanup_days'):
  48. config_vals['cleanup_days'] = \
  49. int(config_vals['cleanup_days'])
  50. if config_vals.get('cleanup_folder'):
  51. config_vals['cleanup_folder'] = \
  52. config_vals['cleanup_folder']
  53. res[fetchmail.id] = config_vals
  54. return res
  55. _columns = {
  56. 'cleanup_days': fields.function(
  57. _get_cleanup_conf,
  58. method=True,
  59. string='Expiration days',
  60. type="integer",
  61. multi='outgoing_mail_config',
  62. help="Number of days before discarding an e-mail"),
  63. 'cleanup_folder': fields.function(
  64. _get_cleanup_conf,
  65. method=True,
  66. string='Expiration folder',
  67. type="char",
  68. multi='outgoing_mail_config',
  69. help="Folder where the discarded e-mail will be moved.")
  70. }
  71. def _cleanup_fetchmail_server(self, server, imap_server):
  72. count, failed = 0, 0
  73. expiration_date = (datetime.now() + relativedelta.relativedelta(
  74. days=-(server.cleanup_days))).strftime('%d-%b-%Y')
  75. search_text = '(UNSEEN BEFORE %s)' % expiration_date
  76. imap_server.select()
  77. result, data = imap_server.search(None, search_text)
  78. for num in data[0].split():
  79. result, data = imap_server.fetch(num, '(RFC822)')
  80. try:
  81. # Mark message as read
  82. imap_server.store(num, '+FLAGS', '\\Seen')
  83. if server.cleanup_folder:
  84. # To move a message, you have to COPY
  85. # then DELETE the message
  86. result = imap_server.copy(num, server.cleanup_folder)
  87. if result[0] == 'OK':
  88. imap_server.store(num, '+FLAGS', '\\Deleted')
  89. imap_server.expunge()
  90. except Exception:
  91. _logger.exception('Failed to cleanup mail from %s server %s.',
  92. server.type, server.name)
  93. failed += 1
  94. count += 1
  95. _logger.info("Fetched %d email(s) on %s server %s; "
  96. "%d succeeded, %d failed.", count, server.type,
  97. server.name, (count - failed), failed)
  98. def fetch_mail(self, cr, uid, ids, context=None):
  99. """ Called before the fetch, in order to clean up
  100. right before retrieving emails. """
  101. if context is None:
  102. context = {}
  103. context['fetchmail_cron_running'] = True
  104. for server in self.browse(cr, uid, ids, context=context):
  105. _logger.info('start cleaning up emails on %s server %s',
  106. server.type, server.name)
  107. context.update({'fetchmail_server_id': server.id,
  108. 'server_type': server.type})
  109. imap_server = False
  110. if server.type == 'imap' and server.cleanup_days > 0:
  111. try:
  112. imap_server = server.connect()
  113. self._cleanup_fetchmail_server(server, imap_server)
  114. except Exception:
  115. _logger.exception("General failure when trying to cleanup "
  116. "mail from %s server %s.",
  117. server.type, server.name)
  118. finally:
  119. if imap_server:
  120. imap_server.close()
  121. imap_server.logout()
  122. return super(FetchmailServer, self).fetch_mail(cr, uid, ids,
  123. context=context)