2010-06-05 06:38:44 +00:00
# -*- coding: utf-8 -*-
2010-04-15 15:43:28 +00:00
##############################################################################
#
2010-06-05 06:38:44 +00:00
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
2010-04-15 15:43:28 +00:00
#
# This program is free software: you can redistribute it and/or modify
2010-06-05 06:38:44 +00:00
# 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.
2010-04-15 15:43:28 +00:00
#
# 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
2010-06-05 06:38:44 +00:00
# GNU Affero General Public License for more details.
2010-04-15 15:43:28 +00:00
#
2010-06-05 06:38:44 +00:00
# You should have received a copy of the GNU Affero General Public License
2010-04-15 15:43:28 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
2011-09-08 01:07:00 +00:00
import logging
2010-04-15 15:43:28 +00:00
import time
from imaplib import IMAP4
2010-06-24 19:53:32 +00:00
from imaplib import IMAP4_SSL
2010-04-19 20:57:36 +00:00
from poplib import POP3
from poplib import POP3_SSL
2010-04-15 15:43:28 +00:00
import netsvc
2010-06-24 19:53:32 +00:00
from osv import osv , fields
2011-02-10 07:34:53 +00:00
import tools
2011-09-08 14:19:41 +00:00
from tools . translate import _
2010-04-15 15:43:28 +00:00
2011-09-08 01:07:00 +00:00
logger = logging . getLogger ( ' fetchmail ' )
2010-04-15 15:43:28 +00:00
2011-09-08 14:19:41 +00:00
class fetchmail_server ( osv . osv ) :
""" Incoming POP/IMAP mail server account """
_name = ' fetchmail.server '
2010-04-15 15:43:28 +00:00
_description = " POP/IMAP Server "
2011-09-08 01:07:00 +00:00
_order = ' priority '
2010-06-24 19:53:32 +00:00
2010-04-15 15:43:28 +00:00
_columns = {
2010-08-19 11:51:57 +00:00
' name ' : fields . char ( ' Name ' , size = 256 , required = True , readonly = False ) ,
' active ' : fields . boolean ( ' Active ' , required = False ) ,
2010-04-15 15:43:28 +00:00
' state ' : fields . selection ( [
2010-08-19 11:51:57 +00:00
( ' draft ' , ' Not Confirmed ' ) ,
( ' done ' , ' Confirmed ' ) ,
] , ' State ' , select = True , readonly = True ) ,
2011-09-08 01:07:00 +00:00
' server ' : fields . char ( ' Server Name ' , size = 256 , required = True , readonly = True , help = " Hostname or IP of the mail server " , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-08-19 11:51:57 +00:00
' port ' : fields . integer ( ' Port ' , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
2010-04-15 15:43:28 +00:00
' type ' : fields . selection ( [
2010-08-19 11:51:57 +00:00
( ' pop ' , ' POP Server ' ) ,
( ' imap ' , ' IMAP Server ' ) ,
2011-09-08 01:07:00 +00:00
] , ' Server Type ' , select = True , required = True , readonly = False ) ,
' is_ssl ' : fields . boolean ( ' SSL/TLS ' , help = " Connections are encrypted with SSL/TLS through a dedicated port (default: IMAPS=993, POP3S=995) " ) ,
' attach ' : fields . boolean ( ' Keep Attachments ' , help = " Whether attachments should be downloaded. "
" If not enabled, incoming emails will be stripped of any attachments before being processed " ) ,
' original ' : fields . boolean ( ' Keep Original ' , help = " Whether a full original copy of each email should be kept for reference "
" and attached to each processed message. This will usually double the size of your message database. " ) ,
' date ' : fields . datetime ( ' Last Fetch Date ' , readonly = True ) ,
' user ' : fields . char ( ' Username ' , size = 256 , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
' password ' : fields . char ( ' Password ' , size = 1024 , required = True , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } ) ,
' action_id ' : fields . many2one ( ' ir.actions.server ' , ' Server Action ' , help = " Optional custom server action to trigger for each incoming mail, "
" on the record that was created or updated by this mail " ) ,
2011-10-01 20:02:47 +00:00
' object_id ' : fields . many2one ( ' ir.model ' , " Create a New Record " , required = True , help = " Process each incoming mail as part of a conversation "
2011-09-08 01:07:00 +00:00
" corresponding to this document type. This will create "
" new documents for new conversations, or attach follow-up "
" emails to the existing conversations (documents). " ) ,
' priority ' : fields . integer ( ' Server Priority ' , readonly = True , states = { ' draft ' : [ ( ' readonly ' , False ) ] } , help = " Defines the order of processing, "
" lower values mean higher priority " ) ,
2011-09-08 14:19:41 +00:00
' message_ids ' : fields . one2many ( ' mail.message ' , ' fetchmail_server_id ' , ' Messages ' , readonly = True ) ,
2010-04-15 15:43:28 +00:00
}
_defaults = {
2011-09-08 01:07:00 +00:00
' state ' : " draft " ,
2011-10-01 20:02:47 +00:00
' type ' : " pop " ,
2011-09-08 01:07:00 +00:00
' active ' : True ,
' priority ' : 5 ,
' attach ' : True ,
2010-04-15 15:43:28 +00:00
}
2010-06-24 19:53:32 +00:00
2011-09-22 13:08:27 +00:00
def default_get ( self , cr , uid , fields , context = None ) :
if context is None :
context = { }
result = super ( fetchmail_server , self ) . default_get ( cr , uid , fields , context = context )
model = context . pop ( ' fetchmail_model ' , False ) or False
if isinstance ( model , basestring ) :
model_id = self . pool . get ( ' ir.model ' ) . search ( cr , uid , [ ( ' model ' , ' = ' , model ) ] , context = context )
result . update (
object_id = model_id [ 0 ] ,
)
return result
2010-04-15 15:43:28 +00:00
def onchange_server_type ( self , cr , uid , ids , server_type = False , ssl = False ) :
port = 0
if server_type == ' pop ' :
port = ssl and 995 or 110
elif server_type == ' imap ' :
port = ssl and 993 or 143
return { ' value ' : { ' port ' : port } }
2010-04-27 14:44:13 +00:00
2010-11-19 13:48:01 +00:00
def set_draft ( self , cr , uid , ids , context = None ) :
2010-04-27 14:44:13 +00:00
self . write ( cr , uid , ids , { ' state ' : ' draft ' } )
return True
2011-02-07 05:33:04 +00:00
2011-09-08 01:07:00 +00:00
def connect ( self , cr , uid , server_id , context = None ) :
if isinstance ( server_id , ( list , tuple ) ) :
server_id = server_id [ 0 ]
server = self . browse ( cr , uid , server_id , context )
if server . type == ' imap ' :
if server . is_ssl :
connection = IMAP4_SSL ( server . server , int ( server . port ) )
else :
connection = IMAP4 ( server . server , int ( server . port ) )
connection . login ( server . user , server . password )
elif server . type == ' pop ' :
if server . is_ssl :
connection = POP3_SSL ( server . server , int ( server . port ) )
else :
connection = POP3 ( server . server , int ( server . port ) )
#TODO: use this to remove only unread messages
#connection.user("recent:"+server.user)
connection . user ( server . user )
connection . pass_ ( server . password )
return connection
2010-11-19 13:48:01 +00:00
def button_confirm_login ( self , cr , uid , ids , context = None ) :
2010-11-23 07:05:05 +00:00
if context is None :
2010-11-19 13:48:01 +00:00
context = { }
for server in self . browse ( cr , uid , ids , context = context ) :
2010-04-22 13:44:47 +00:00
try :
2011-09-08 01:07:00 +00:00
connection = server . connect ( )
server . write ( { ' state ' : ' done ' } )
2010-11-04 11:19:28 +00:00
except Exception , e :
2011-09-08 01:07:00 +00:00
logger . exception ( " Failed to connect to %s server %s " , server . type , server . name )
2011-09-14 12:07:53 +00:00
raise osv . except_osv ( _ ( " Connection test failed! " ) , _ ( " Here is what we got instead: \n %s " ) % tools . ustr ( e ) )
2011-09-08 01:07:00 +00:00
finally :
try :
if connection :
if server . type == ' imap ' :
connection . close ( )
elif server . type == ' pop ' :
connection . quit ( )
except Exception :
# ignored, just a consequence of the previous exception
pass
2010-11-04 11:19:28 +00:00
return True
2010-11-19 13:48:01 +00:00
def _fetch_mails ( self , cr , uid , ids = False , context = None ) :
2010-11-04 11:19:28 +00:00
if not ids :
2011-09-08 01:07:00 +00:00
ids = self . search ( cr , uid , [ ( ' state ' , ' = ' , ' done ' ) ] )
2010-11-04 11:19:28 +00:00
return self . fetch_mail ( cr , uid , ids , context = context )
2010-11-19 13:48:01 +00:00
def fetch_mail ( self , cr , uid , ids , context = None ) :
2011-09-08 01:07:00 +00:00
""" WARNING: meant for cron usage only - will commit() after each email! """
2010-11-23 07:05:05 +00:00
if context is None :
2010-11-19 13:48:01 +00:00
context = { }
2011-09-08 01:07:00 +00:00
mail_thread = self . pool . get ( ' mail.thread ' )
2010-11-04 11:19:28 +00:00
action_pool = self . pool . get ( ' ir.actions.server ' )
2010-11-19 13:48:01 +00:00
for server in self . browse ( cr , uid , ids , context = context ) :
2011-09-08 01:07:00 +00:00
logger . info ( ' start checking for new emails on %s server %s ' , server . type , server . name )
2011-09-08 14:19:41 +00:00
context . update ( { ' fetchmail_server_id ' : server . id , ' server_type ' : server . type } )
2010-11-04 11:19:28 +00:00
count = 0
2011-02-28 09:03:44 +00:00
if server . type == ' imap ' :
try :
2011-09-08 01:07:00 +00:00
imap_server = server . connect ( )
2010-04-22 13:44:47 +00:00
imap_server . select ( )
2010-08-19 11:51:57 +00:00
result , data = imap_server . search ( None , ' (UNSEEN) ' )
2010-04-22 13:44:47 +00:00
for num in data [ 0 ] . split ( ) :
result , data = imap_server . fetch ( num , ' (RFC822) ' )
2011-09-08 01:07:00 +00:00
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 )
2010-06-24 19:53:32 +00:00
if res_id and server . action_id :
2011-09-08 01:07:00 +00:00
action_pool . run ( cr , uid , [ server . action_id . id ] , { ' active_id ' : res_id , ' active_ids ' : [ res_id ] } )
2010-04-22 13:44:47 +00:00
imap_server . store ( num , ' +FLAGS ' , ' \\ Seen ' )
2011-09-08 01:07:00 +00:00
cr . commit ( )
2010-06-24 19:53:32 +00:00
count + = 1
2011-09-08 01:07:00 +00:00
logger . info ( " fetched/processed %s email(s) on %s server %s " , count , server . type , server . name )
2011-02-28 09:03:44 +00:00
except Exception , e :
2011-09-08 01:07:00 +00:00
logger . exception ( " Failed to fetch mail from %s server %s " , server . type , server . name )
2011-02-28 09:03:44 +00:00
finally :
2011-03-03 10:37:40 +00:00
if imap_server :
imap_server . close ( )
imap_server . logout ( )
2011-02-28 09:03:44 +00:00
elif server . type == ' pop ' :
try :
2011-09-08 01:07:00 +00:00
pop_server = server . connect ( )
2010-04-22 13:44:47 +00:00
( numMsgs , totalSize ) = pop_server . stat ( )
2011-02-28 09:03:44 +00:00
pop_server . list ( )
2010-04-22 13:44:47 +00:00
for num in range ( 1 , numMsgs + 1 ) :
( header , msges , octets ) = pop_server . retr ( num )
msg = ' \n ' . join ( msges )
2011-09-08 01:07:00 +00:00
res_id = mail_thread . message_process ( cr , uid , server . object_id . model ,
msg ,
save_original = server . original ,
strip_attachments = ( not server . attach ) ,
context = context )
2010-06-24 19:53:32 +00:00
if res_id and server . action_id :
2011-09-08 01:07:00 +00:00
action_pool . run ( cr , uid , [ server . action_id . id ] , { ' active_id ' : res_id , ' active_ids ' : [ res_id ] } )
2010-04-22 13:44:47 +00:00
pop_server . dele ( num )
2011-09-08 01:07:00 +00:00
cr . commit ( )
logger . info ( " fetched/processed %s email(s) on %s server %s " , numMsgs , server . type , server . name )
2011-02-28 09:03:44 +00:00
except Exception , e :
2011-09-08 01:07:00 +00:00
logger . exception ( " Failed to fetch mail from %s server %s " , server . type , server . name )
2011-02-28 09:03:44 +00:00
finally :
2011-03-03 10:37:40 +00:00
if pop_server :
pop_server . quit ( )
2011-09-08 01:07:00 +00:00
server . write ( { ' date ' : time . strftime ( tools . DEFAULT_SERVER_DATETIME_FORMAT ) } )
2010-04-15 15:43:28 +00:00
return True
2010-04-19 20:57:36 +00:00
2011-08-22 17:16:59 +00:00
class mail_message ( osv . osv ) :
_inherit = " mail.message "
2010-04-15 15:43:28 +00:00
_columns = {
2011-09-08 14:19:41 +00:00
' fetchmail_server_id ' : fields . many2one ( ' fetchmail.server ' , " Inbound Mail Server " ,
readonly = True ,
select = True ,
oldname = ' server_id ' ) ,
2010-04-15 15:43:28 +00:00
}
2010-06-24 19:53:32 +00:00
2010-06-25 09:57:41 +00:00
def create ( self , cr , uid , values , context = None ) :
2010-11-23 07:05:05 +00:00
if context is None :
2010-06-25 09:57:41 +00:00
context = { }
2011-09-08 14:19:41 +00:00
fetchmail_server_id = context . get ( ' fetchmail_server_id ' )
if fetchmail_server_id :
values [ ' fetchmail_server_id ' ] = fetchmail_server_id
2011-08-22 17:16:59 +00:00
res = super ( mail_message , self ) . create ( cr , uid , values , context = context )
2010-06-25 09:57:41 +00:00
return res
def write ( self , cr , uid , ids , values , context = None ) :
2010-11-23 07:05:05 +00:00
if context is None :
2010-06-25 09:57:41 +00:00
context = { }
2011-09-08 14:19:41 +00:00
fetchmail_server_id = context . get ( ' fetchmail_server_id ' )
if fetchmail_server_id :
values [ ' fetchmail_server_id ' ] = server_id
2011-08-22 17:16:59 +00:00
res = super ( mail_message , self ) . write ( cr , uid , ids , values , context = context )
2010-06-25 09:57:41 +00:00
return res
2010-06-24 19:53:32 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: