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.

166 lines
7.0 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 openerp.osv import orm, fields
  23. from dateutil import relativedelta
  24. from datetime import datetime
  25. from server_environment import serv_config
  26. _logger = logging.getLogger(__name__)
  27. class FetchmailServer(orm.Model):
  28. """Incoming POP/IMAP mail server account"""
  29. _inherit = 'fetchmail.server'
  30. def _get_cleanup_conf(self, cursor, uid, ids, name, args, context=None):
  31. """
  32. Return configuration
  33. """
  34. res = {}
  35. for fetchmail in self.browse(cursor, uid, ids):
  36. global_section_name = 'incoming_mail'
  37. # default vals
  38. config_vals = {'cleanup_days': False,
  39. 'purge_days': False,
  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. # convert string values to integer
  48. if config_vals['cleanup_days']:
  49. config_vals['cleanup_days'] = int(config_vals['cleanup_days'])
  50. if config_vals['purge_days']:
  51. config_vals['purge_days'] = int(config_vals['purge_days'])
  52. res[fetchmail.id] = config_vals
  53. return res
  54. _columns = {
  55. 'cleanup_days': fields.function(
  56. _get_cleanup_conf,
  57. method=True,
  58. string='Expiration days',
  59. type="integer",
  60. multi='outgoing_mail_config',
  61. help="Number of days before marking an e-mail as read"),
  62. 'cleanup_folder': fields.function(
  63. _get_cleanup_conf,
  64. method=True,
  65. string='Expiration folder',
  66. type="char",
  67. multi='outgoing_mail_config',
  68. help="Folder where an e-mail marked as read will be moved."),
  69. 'purge_days': fields.function(
  70. _get_cleanup_conf,
  71. method=True,
  72. string='Deletion days',
  73. type="integer",
  74. multi='outgoing_mail_config',
  75. help="Number of days before removing an e-mail"),
  76. }
  77. def _cleanup_fetchmail_server(self, server, imap_server):
  78. count, failed = 0, 0
  79. expiration_date = (datetime.now() + relativedelta.relativedelta(
  80. days=-(server.cleanup_days))).strftime('%d-%b-%Y')
  81. search_text = '(UNSEEN BEFORE %s)' % expiration_date
  82. imap_server.select()
  83. result, data = imap_server.search(None, search_text)
  84. for num in data[0].split():
  85. try:
  86. # Mark message as read
  87. imap_server.store(num, '+FLAGS', '\\Seen')
  88. if server.cleanup_folder:
  89. # To move a message, you have to COPY
  90. # then DELETE the message
  91. result = imap_server.copy(num, server.cleanup_folder)
  92. if result[0] == 'OK':
  93. imap_server.store(num, '+FLAGS', '\\Deleted')
  94. except Exception:
  95. _logger.exception('Failed to cleanup mail from %s server %s.',
  96. server.type, server.name)
  97. failed += 1
  98. count += 1
  99. _logger.info("Marked %d email(s) as read on %s server %s; "
  100. "%d succeeded, %d failed.", count, server.type,
  101. server.name, (count - failed), failed)
  102. def _purge_fetchmail_server(self, server, imap_server):
  103. # Purging e-mails older than the purge date, if available
  104. count, failed = 0, 0
  105. purge_date = (datetime.now() + relativedelta.relativedelta(
  106. days=-(server.purge_days))).strftime('%d-%b-%Y')
  107. search_text = '(BEFORE %s)' % purge_date
  108. imap_server.select()
  109. result, data = imap_server.search(None, search_text)
  110. for num in data[0].split():
  111. try:
  112. # Delete message
  113. imap_server.store(num, '+FLAGS', '\\Deleted')
  114. except Exception:
  115. _logger.exception('Failed to remove mail from %s server %s.',
  116. server.type, server.name)
  117. failed += 1
  118. count += 1
  119. _logger.info("Removed %d email(s) on %s server %s; "
  120. "%d succeeded, %d failed.", count, server.type,
  121. server.name, (count - failed), failed)
  122. def fetch_mail(self, cr, uid, ids, context=None):
  123. """ Called before the fetch, in order to clean up
  124. right before retrieving emails. """
  125. if context is None:
  126. context = {}
  127. context['fetchmail_cron_running'] = True
  128. for server in self.browse(cr, uid, ids, context=context):
  129. _logger.info('start cleaning up emails on %s server %s',
  130. server.type, server.name)
  131. context.update({'fetchmail_server_id': server.id,
  132. 'server_type': server.type})
  133. imap_server = False
  134. if server.type == 'imap':
  135. try:
  136. imap_server = server.connect()
  137. if server.cleanup_days > 0:
  138. self._cleanup_fetchmail_server(server, imap_server)
  139. if server.purge_days > 0:
  140. self._purge_fetchmail_server(server, imap_server)
  141. # Do the final cleanup: delete all messages
  142. # flagged as deleted
  143. imap_server.expunge()
  144. except Exception:
  145. _logger.exception("General failure when trying to cleanup "
  146. "mail from %s server %s.",
  147. server.type, server.name)
  148. finally:
  149. if imap_server:
  150. imap_server.close()
  151. imap_server.logout()
  152. return super(FetchmailServer, self).fetch_mail(cr, uid, ids,
  153. context=context)