[FIX] Add the copyright of OpenERP S.A.

[REF] Remove unless code 
[IMP] Use the new mailgate.thread, mailgate.message concept for the
communication history of a crm.* object (can be used with an other
        object with the thread_id#mailgate.thread) field
[IMP] Add a logging support

bzr revid: stephane@openerp.com-20100611130716-wpclu61sqza7lg5h
This commit is contained in:
Stephane Wirtel
2010-06-11 15:07:16 +02:00
parent 220eac1612
commit 58e9a51264
@@ -3,7 +3,8 @@
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-TODAY OpenERP S.A. (http://www.openerp.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@@ -22,14 +23,18 @@
import re
import smtplib
import email, mimetypes
import email
import mimetypes
from email.Header import decode_header
from email.MIMEText import MIMEText
import xmlrpclib
import os
import binascii
import time, socket
import time
import socket
import logging
import sys
import optparse
email_re = re.compile(r"([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6})")
case_re = re.compile(r"\[([0-9]+)\]", re.UNICODE)
@@ -89,7 +94,6 @@ def html2plaintext(html, body_id=None, encoding='utf-8'):
html = html.replace('<h2>', '**').replace('</h2>', '**')
html = html.replace('<h1>', '**').replace('</h1>', '**')
html = html.replace('<em>', '/').replace('</em>', '/')
# the only line breaks we respect is those of ending tags and
# breaks
@@ -101,14 +105,7 @@ def html2plaintext(html, body_id=None, encoding='utf-8'):
html = re.sub('<br\s*/>', '\n', html)
html = html.replace(' ' * 2, ' ')
# for all other tags we failed to clean up, just remove then and
# complain about them on the stderr
def desperate_fixer(g):
#print >>sys.stderr, "failed to clean up %s" % str(g.group())
return ' '
html = re.sub('<.*?>', desperate_fixer, html)
html = re.sub('<.*?>', ' ', html)
# lstrip all lines
html = '\n'.join([x.lstrip() for x in html.splitlines()])
@@ -166,10 +163,11 @@ class email_parser(object):
pass
return s.decode('latin1')
def _decode_header(self, s):
def _decode_header(self, text):
from email.Header import decode_header
s = decode_header(s.replace('\r', ''))
return ''.join(map(lambda x:self._to_decode(x[0], [x[1]]), s or []))
if text:
text = decode_header(text.replace('\r', ''))
return ''.join(map(lambda x:self._to_decode(x[0], [x[1]]), text or []))
def msg_new(self, msg):
message = self.msg_body_get(msg)
@@ -188,14 +186,25 @@ class email_parser(object):
}
data.update(self.partner_get(msg_from))
try:
id = self.rpc(self.model, 'create', data)
self.rpc(self.model, 'history', [id], 'Receive', True, msg_to, message['body'], msg_from, False, {'model' : self.model})
#self.rpc(self.model, 'case_open', [id])
except Exception, e:
if getattr(e, 'faultCode', '') and 'AccessError' in e.faultCode:
e = '\n\nThe Specified user does not have an access to the CRM case.'
print e
values = {
'message_ids' : [
(0, 0, {
'model_id' : self.rpc('ir.model', 'search', [('name', '=', self.model)])[0],
'date' : time.strftime('%Y-%m-%d %H:%M:%S'),
'description' : message['body'],
'email_from' : msg_from,
'email_to' : msg_to,
'name' : 'Receive',
'history' : True,
'user_id' : self.rpc.user_id,
}
)
]
}
thread_id = self.rpc('mailgate.thread', 'create', values)
data['thread_id'] = thread_id
oid = self.rpc(self.model, 'create', data)
attachments = message['attachment']
for attach in attachments or []:
data_attach = {
@@ -204,30 +213,19 @@ class email_parser(object):
'datas_fname': str(attach),
'description': 'Mail attachment',
'res_model': self.model,
'res_id': id
'res_id': oid
}
self.rpc('ir.attachment', 'create', data_attach)
return id
# #change the return type format to dictionary
# {
# 'body':'body part',
# 'attachment':{
# 'file_name':'file data',
# 'file_name':'file data',
# 'file_name':'file data',
# }
# }
return (oid, thread_id,)
def msg_body_get(self, msg):
message = {};
message['body'] = '';
message['attachment'] = {};
message = {
'body' : '',
'attachment' : {},
}
attachment = message['attachment'];
counter = 1;
def replace(match):
return ''
for part in msg.walk():
if part.get_content_maintype() == 'multipart':
@@ -237,27 +235,23 @@ class email_parser(object):
buf = part.get_payload(decode=True)
if buf:
txt = self._to_decode(buf, part.get_charsets())
txt = re.sub("<(\w)>", replace, txt)
txt = re.sub("<\/(\w)>", replace, txt)
txt = re.sub("<\/?(\w)>", '', txt)
if txt and part.get_content_subtype() == 'plain':
message['body'] += txt
elif txt and part.get_content_subtype() == 'html':
elif txt and part.get_content_subtype() == 'html':
message['body'] += html2plaintext(txt)
filename = part.get_filename();
if filename :
attachment[filename] = part.get_payload(decode=True);
elif part.get_content_maintype()=='application' or part.get_content_maintype()=='image' or part.get_content_maintype()=='text':
elif part.get_content_maintype() in ('application', 'image', 'text'):
filename = part.get_filename();
if filename :
attachment[filename] = part.get_payload(decode=True);
else:
if not filename :
filename = 'attach_file'+str(counter);
counter += 1;
attachment[filename] = part.get_payload(decode=True);
#end if
#end if
attachment[filename] = part.get_payload(decode=True);
message['attachment'] = attachment
#end for
return message
@@ -316,22 +310,42 @@ class email_parser(object):
}
self.rpc('ir.attachment', 'create', data_attach)
self.rpc(self.model, 'history', [id], 'Send', True, self._decode_header(msg['To']), body['body'], self._decode_header(msg['From']), False, {'model' : self.model})
self.create_message(id, msg['From'], msg['To'], 'Send', message['body'])
return id
def create_message(self, oid, email_from, email_to, name, body):
"""
This functions creates a message in the thread
> create_message(id, msg['From'], msg['To'], 'Send', message['body'])
"""
values = {
'thread_id' : self.rpc(self.model, 'read', [oid], ['thread_id'])[0]['thread_id'][0],
'model_id' : self.rpc('ir.model', 'search', [('name', '=', self.model)])[0],
'res_id' : oid,
'date' : time.strftime('%Y-%m-%d %H:%M:%S'),
'description' : body,
'email_from' : self._decode_header(email_from),
'email_to' : self._decode_header(email_to),
'name' : name,
'history' : True,
'user_id' : self.rpc.user_id,
}
return self.rpc('mailgate.message', 'create', values)
def msg_send(self, msg, emails, priority=None):
if not len(emails):
if not emails:
return False
del msg['To']
msg['To'] = emails[0]
if len(emails)>1:
if 'Cc' in msg:
del msg['Cc']
if len(emails) > 1:
msg['Cc'] = ','.join(emails[1:])
del msg['Reply-To']
msg['Reply-To'] = self.email
if priority:
msg['X-Priority'] = priorities.get(priority, '3 (Normal)')
s = smtplib.SMTP()
s.connect()
s.sendmail(self.email, emails, msg.as_string())
@@ -343,11 +357,6 @@ class email_parser(object):
body = message['body']
act = 'case_open'
self.rpc(self.model, act, [id])
#body2 = '\n'.join(map(lambda l: '> '+l, (body or '').split('\n')))
#data = {
# 'description':body,
#}
#self.rpc(self.model, 'write', [id], data)
attachments = message['attachment']
for attach in attachments or []:
data_attach = {
@@ -360,14 +369,16 @@ class email_parser(object):
}
self.rpc('ir.attachment', 'create', data_attach)
self.rpc(self.model, 'history', [id], 'Send', True, self._decode_header(msg['To']), message['body'], self._decode_header(msg['From']), False, {'model' : self.model})
self.create_message(id, msg['From'], msg['To'], 'Send', message['body'])
return id
def msg_test(self, msg, case_str):
if not case_str:
return (False, False)
emails = self.rpc(self.model, 'emails_get', int(case_str))
return (int(case_str), emails)
case_id = int(case_str)
emails = self.rpc(self.model, 'emails_get', [case_id])
return (case_id, emails)
def parse(self, msg):
case_str = reference_re.search(msg.get('References', ''))
@@ -377,23 +388,37 @@ class email_parser(object):
case_str = case_re.search(msg.get('Subject', ''))
if case_str:
case_str = case_str.group(1)
logging.info("email: %s -> %s -- %s", msg['From'], self.email, msg['Subject'])
(case_id, emails) = self.msg_test(msg, case_str)
thread_id = None
if case_id:
if emails[0] and self.email_get(emails[0])==self.email_get(self._decode_header(msg['From'])):
values = self.rpc(self.model, 'read', [case_id], ['thread_id'])
if values:
thread_id = values[0]['thread_id'][0]
emails = emails[str(thread_id)]
user_email = filter(None, emails['user_email'])[0]
if user_email and self.email_get(user_email) == self.email_get(self._decode_header(msg['From'])):
self.msg_user(msg, case_id)
else:
self.msg_partner(msg, case_id)
else:
case_id = self.msg_new(msg)
subject = self._decode_header(msg['subject'])
if msg.get('Subject', ''):
del msg['Subject']
msg['Subject'] = '['+str(case_id)+'] '+subject
msg['Message-Id'] = '<'+str(time.time())+'-openerpcrm-'+str(case_id)+'@'+socket.gethostname()+'>'
case_id, thread_id = self.msg_new(msg)
subject = self._decode_header(msg['Subject'])
msg['Subject'] = "[%s] %s" % (case_id, subject,)
msg['Message-Id'] = "<%s-openerpcrm-%s@%s>" % (time.time(), case_id, socket.gethostname(),)
emails = self.rpc(self.model, 'emails_get', case_id)
priority = emails[3]
em = [emails[0], emails[1]] + (emails[2] or '').split(',')
logging.info(" case: %r", case_id)
logging.info(" thread: %r", thread_id)
values = self.rpc(self.model, 'emails_get', [case_id])
emails = values[str(thread_id)]
priority = emails.get('piority', [3])[0]
em = emails['user_email'] + emails['email_from'] + emails['email_cc']
emails = map(self.email_get, filter(None, em))
mm = [self._decode_header(msg['From']), self._decode_header(msg['To'])]+self._decode_header(msg.get('Cc', '')).split(',')
@@ -405,13 +430,11 @@ class email_parser(object):
except:
if self.email_default:
a = self._decode_header(msg['Subject'])
del msg['Subject']
msg['Subject'] = '[OpenERP-CaseError] ' + a
self.msg_send(msg, self.email_default.split(','))
return case_id, emails
return case_id, thread_id, emails
if __name__ == '__main__':
import sys, optparse
parser = optparse.OptionParser(usage='usage: %prog [options]', version='%prog v1.0')
group = optparse.OptionGroup(parser, "Note",
"This program parse a mail from standard input and communicate "
@@ -426,8 +449,10 @@ if __name__ == '__main__':
parser.add_option("--host", dest="host", help="Hostname of the Open ERP Server", default="localhost")
parser.add_option("--port", dest="port", help="Port of the Open ERP Server", default="8069")
(options, args) = parser.parse_args()
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)s %(message)s")
parser = email_parser(options.userid, options.password, options.model, options.email, options.default, dbname=options.dbname, host=options.host, port=options.port)
msg_txt = email.message_from_file(sys.stdin)