[ADD] mail_gate : new module for mail_gate and Remove the gateway stuff from crm

bzr revid: hmo@tinyerp.com-20100103065757-h4yakktaegxpqtm7
This commit is contained in:
Harry (Open ERP) 2010-01-03 12:27:57 +05:30
commit 3478962de6
30 changed files with 1263 additions and 380 deletions

View File

@ -20,9 +20,10 @@
##############################################################################
import crm
import crm_mailgate
import crm_segmentation
import crm_meeting
import crm_config
import crm_meeting
import crm_lead
import crm_phonecall
import crm_opportunity
@ -31,6 +32,7 @@ import crm_fundraising
import crm_job
import crm_helpdesk
import report
import wizard

View File

@ -46,7 +46,8 @@ between mails and Open ERP.""",
'website': 'http://www.openerp.com',
'depends': ['base',
'caldav',
'process'
'process',
'mail_gateway',
],
'init_xml': ['crm_data.xml',
'crm_meeting_data.xml',

View File

@ -32,7 +32,7 @@ import tools
from osv import fields,osv,orm
from osv.orm import except_orm
from scripts.openerp_mailgate import openerp_mailgate
import email
import netsvc
from poplib import POP3, POP3_SSL
@ -73,8 +73,7 @@ class crm_case_section(osv.osv):
'user_id': fields.many2one('res.users', 'Responsible User'),
'reply_to': fields.char('Reply-To', size=64, help="The email address put in the 'Reply-To' of all emails sent by Open ERP about cases in this section"),
'parent_id': fields.many2one('crm.case.section', 'Parent Section'),
'child_ids': fields.one2many('crm.case.section', 'parent_id', 'Child Sections'),
"gateway_ids" : fields.one2many("crm.email.gateway",'section_id',"Email Gateways"),
'child_ids': fields.one2many('crm.case.section', 'parent_id', 'Child Sections'),
'calendar' : fields.boolean('Calendar', help='Allows to show calendar'),
}
_defaults = {
@ -209,148 +208,6 @@ class crm_case_section(osv.osv):
return res
crm_case_section()
class crm_email_gateway_server(osv.osv):
_name = "crm.email.gateway.server"
_description = "Email Gateway Server"
_columns = {
'name': fields.char('Server Address',size=64,required=True ,help="IMAP/POP Address Of Email gateway Server"),
'login': fields.char('User',size=64,required=True,help="User Login Id of Email gateway"),
'password': fields.char('Password',size=64,required=True,help="User Password Of Email gateway"),
'server_type': fields.selection([("pop","POP"),("imap","Imap")],"Type of Server", required=True, help="Type of Email gateway Server"),
'port': fields.integer("Port" , help="Port Of Email gateway Server. If port is omitted, the standard POP3 port (110) is used for POP EMail Server and the standard IMAP4 port (143) is used for IMAP Sever."),
'ssl': fields.boolean('SSL',help ="Use Secure Authentication"),
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the email gateway server without removing it."),
}
_defaults = {
'server_type':lambda * a:'pop',
'active':lambda * a:True,
}
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}}
crm_email_gateway_server()
class crm_email_gateway(osv.osv):
_name = "crm.email.gateway"
_description = "Email Gateway"
_columns = {
'name': fields.char('Name',size=64,help="Name of Mail Gateway."),
'server_id': fields.many2one('crm.email.gateway.server',"Gateway Server", required=True),
'to_email_id': fields.char('TO', size=64, help="Email address used in the From field of outgoing messages"),
'cc_email_id': fields.char('CC',size=64,help="Default eMail in case of any trouble."),
'section_id': fields.many2one('crm.case.section',"Section",required=True),
'mail_history': fields.one2many("crm.email.history","gateway_id","History", readonly=True)
}
def _fetch_mails(self, cr, uid, ids=False, context={}):
'''
Function called by the scheduler to fetch mails
'''
cr.execute('select * from crm_email_gateway gateway \
inner join crm_email_gateway_server server \
on server.id = gateway.server_id where server.active = True')
ids2 = map(lambda x: x[0], cr.fetchall() or [])
return self.fetch_mails(cr, uid, ids=ids2, context=context)
def parse_mail(self, cr, uid, gateway_id, email_message, email_parser=None, context={}):
msg_id = case_id = note = False
user_obj = self.pool.get('res.users')
mail_history_obj = self.pool.get('crm.email.history')
users = user_obj.read(cr, uid, uid, ['password'])
mailgateway = self.browse(cr, uid, gateway_id, context=context)
try :
if not email_parser:
email_parser = openerp_mailgate.email_parser(uid, users['password'], mailgateway.section_id.id,
mailgateway.to_email_id or '', mailgateway.cc_email_id or '', dbname=cr.dbname,
host=tools.config['interface'] or 'localhost', port=tools.config['port'] or '8069')
msg_txt = email.message_from_string(email_message)
msg_id = msg_txt['Message-ID']
case_id = email_parser.parse(msg_txt)[0]
except Exception, e:
note = "Error in Parsing Mail: %s " %(str(e))
netsvc.Logger().notifyChannel('Emailgate:Parsing mail:%s' % (mailgateway.name or
'%s (%s)'%(mailgateway.server_id.login, mailgateway.server_id.name)), netsvc.LOG_ERROR, str(e))
mail_history_obj.create(cr, uid, {'name':msg_id, 'case_id': case_id, 'gateway_id':mailgateway.id, 'note':note})
return case_id,note
def fetch_mails(self, cr, uid, ids=[], section_ids=[], context={}):
if len(section_ids):
casesection_obj = self.pool.get('crm.case.section')
for section in casesection_obj.read(cr, uid, section_ids, ['gateway_ids']):
ids += section['gateway_ids']
log_messages = []
for mailgateway in self.browse(cr, uid, ids):
try :
mailgate_server = mailgateway.server_id
if not mailgate_server.active:
continue
mailgate_name = mailgateway.name or "%s (%s)" % (mailgate_server.login, mailgate_server.name)
log_messages.append("Mail Server : %s" % mailgate_name)
log_messages.append("="*40)
new_messages = []
if mailgate_server.server_type == 'pop':
if mailgate_server.ssl:
pop_server = POP3_SSL(mailgate_server.name or 'localhost', mailgate_server.port or 110)
else:
pop_server = POP3(mailgate_server.name or 'localhost', mailgate_server.port or 110)
pop_server.user(mailgate_server.login)
pop_server.pass_(mailgate_server.password)
pop_server.list()
(numMsgs, totalSize) = pop_server.stat()
for i in range(1, numMsgs + 1):
(header, msges, octets) = pop_server.retr(i)
case_id, note = self.parse_mail(cr, uid, mailgateway.id, '\n'.join(msges))
log = ''
if case_id:
log = _('Case Successfull Created : %d'% case_id)
if note:
log = note
log_messages.append(log)
new_messages.append(i)
pop_server.quit()
elif mailgate_server.server_type == 'imap':
if mailgate_server.ssl:
imap_server = IMAP4_SSL(mailgate_server.name or 'localhost', mailgate_server.port or 143)
else:
imap_server = IMAP4(mailgate_server.name or 'localhost', mailgate_server.port or 143)
imap_server.login(mailgate_server.login, mailgate_server.password)
imap_server.select()
typ, data = imap_server.search(None, '(UNSEEN)')
for num in data[0].split():
typ, data = imap_server.fetch(num, '(RFC822)')
case_id, note = self.parse_mail(cr, uid, mailgateway.id, data[0][1])
log = ''
if case_id:
log = 'Case Successfully Created : %d'% case_id
if note:
log = note
log_messages.append(log)
new_messages.append(num)
imap_server.close()
imap_server.logout()
except Exception, e:
log_messages.append("Error in Fetching Mail: %s " %(str(e)))
netsvc.Logger().notifyChannel('Emailgate:Fetching mail:[%d]%s' % (mailgate_server.id, mailgate_server.name), netsvc.LOG_ERROR, str(e))
log_messages.append("-"*25)
log_messages.append("Total Read Mail: %d\n\n" %(len(new_messages)))
return log_messages
crm_email_gateway()
class crm_case_categ(osv.osv):
_name = "crm.case.categ"
_description = "Category of case"
@ -961,11 +818,8 @@ class crm_case(osv.osv):
data['user_id'] = uid
self.write(cr, uid, ids, data)
self._action(cr,uid, cases, 'open')
return True
def emails_get(self, cr, uid, id, context={}):
case = self.browse(cr, uid, id)
return ((case.user_id and case.user_id.address_id and case.user_id.address_id.email) or False, case.email_from, case.email_cc, case.priority)
return True
def case_cancel(self, cr, uid, ids, *args):
cases = self.browse(cr, uid, ids)
@ -1040,19 +894,6 @@ class crm_case_history(osv.osv):
}
crm_case_history()
class crm_email_history(osv.osv):
_name = "crm.email.history"
_description = "Email History"
_columns = {
'name': fields.char('Message Id', size=64, help="Message Id in Email Server."),
'case_id': fields.many2one('crm.case',"Case"),
'gateway_id': fields.many2one('crm.email.gateway',"Email Gateway", required=True),
'note': fields.text('Notes'),
}
_order = 'id desc'
crm_email_history()
class crm_email_add_cc_wizard(osv.osv_memory):
_name = "crm.email.add.cc"
_description = "Email Add CC"

View File

@ -35,12 +35,19 @@ class crm_claim(osv.osv):
'inherit_case_id': fields.many2one('crm.case','Case',ondelete='cascade'),
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -64,7 +71,31 @@ class crm_claim(osv.osv):
def case_escalate(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
def case_pending(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_claim()

View File

@ -65,18 +65,7 @@
<field eval="'crm.case.rule'" name="model"/>
<field eval="'_check'" name="function"/>
<field eval="'()'" name="args"/>
</record>
<record id="ir_cron_crm_email_gateway_action" model="ir.cron">
<field name="name">Check Email (Fetchmail)</field>
<field name="interval_number">5</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'crm.email.gateway'" name="model"/>
<field eval="'_fetch_mails'" name="function"/>
<field eval="'()'" name="args"/>
</record>
</record>
</data>
</openerp>

View File

@ -41,12 +41,19 @@ class crm_fundraising(osv.osv):
'inherit_case_id': fields.many2one('crm.case','Case',ondelete='cascade'),
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -68,6 +75,30 @@ class crm_fundraising(osv.osv):
def case_escalate(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
def case_pending(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_fundraising()
crm_fundraising()

View File

@ -42,12 +42,19 @@ class crm_helpdesk(osv.osv):
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -67,7 +74,29 @@ class crm_helpdesk(osv.osv):
def case_reset(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_reset',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_helpdesk()

View File

@ -40,12 +40,19 @@ class crm_job(osv.osv):
'inherit_case_id': fields.many2one('crm.case','Case',ondelete='cascade'),
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -65,5 +72,29 @@ class crm_job(osv.osv):
def case_cancel(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_cancel',cr,uid,ids,*args,**argv)
def case_reset(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_reset',cr,uid,ids,*args,**argv)
return self._map_ids('case_reset',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_job()

View File

@ -42,12 +42,19 @@ class crm_lead(osv.osv):
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -72,5 +79,28 @@ class crm_lead(osv.osv):
return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_lead()

100
addons/crm/crm_mailgate.py Normal file
View File

@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
import re
import os
import mx.DateTime
import base64
from tools.translate import _
import tools
from osv import fields,osv,orm
from osv.orm import except_orm
class crm_cases(osv.osv):
_name = "crm.case"
_inherit = "crm.case"
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
return self.create(cr, uid, data)
def msg_update(self, cr, uid, id, msg, data={}, default_act='pending'):
mailgate_obj = self.pool.get('mail.gateway')
msg_actions, body_data = mailgate_obj.msg_act_get(msg)
data.update({
'description': body_data,
'history_line': [(0, 0, {'description': body_data, 'email': msg['From']})],
})
act = 'case_'+default_act
if 'state' in msg_actions:
if msg_actions['state'] in ['draft','close','cancel','open','pending']:
act = 'case_' + msg_actions['state']
for k1,k2 in [('cost','planned_cost'),('revenue','planned_revenue'),('probability','probability')]:
try:
data[k2] = float(msg_actions[k1])
except:
pass
if 'priority' in msg_actions:
if msg_actions['priority'] in ('1','2','3','4','5'):
data['priority'] = msg_actions['priority']
if 'partner' in msg_actions:
data['email_from'] = msg_actions['partner'][:128]
self.write(cr, uid, [id], data)
getattr(self,act)(cr, uid, [id])
return True
def emails_get(self, cr, uid, ids, context={}):
res = []
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
for case in self.browse(cr, uid, select):
user_email = (case.user_id and case.user_id.address_id and case.user_id.address_id.email) or False
res += [(user_email, case.email_from, case.email_cc, case.priority)]
if isinstance(ids, (str, int, long)):
return len(res) and res[0] or False
return res
def msg_send(self, cr, uid, id, *args, **argv):
return True
crm_cases()

View File

@ -290,13 +290,19 @@ class crm_meeting(osv.osv):
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
return self._map_ids('onchange_case_id',cr,uid,ids,*args,**argv)
@ -314,7 +320,30 @@ class crm_meeting(osv.osv):
return self._map_ids('case_cancel',cr,uid,ids,*args,**argv)
def case_reset(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_reset',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_meeting()

View File

@ -42,12 +42,19 @@ class crm_opportunity(osv.osv):
'inherit_case_id': fields.many2one('crm.case','Case',ondelete='cascade'),
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -71,7 +78,31 @@ class crm_opportunity(osv.osv):
def case_escalate(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
def case_pending(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_opportunity()

View File

@ -40,12 +40,19 @@ class crm_phonecall(osv.osv):
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -67,7 +74,31 @@ class crm_phonecall(osv.osv):
def case_escalate(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
def case_pending(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_phonecall()

View File

@ -42,32 +42,7 @@
<field name="allow_unlink" select="2"/>
<field name="calendar" select="2"/>
</group>
<field name="reply_to" select="2"/>
<field name="gateway_ids" widget="one2many_list" nolabel="1" colspan="4">
<tree string="Email Gateway" editable="bottom">
<field name="name" />
<field name="server_id" />
</tree>
<form string="Email Gateway">
<field name="name"/>
<field name="server_id" />
<field name="to_email_id"/>
<field name="cc_email_id" />
<field name="mail_history" widget="one2many_list" nolabel="1" colspan="4">
<tree string="Email History">
<field name="name"/>
<field name="case_id"/>
<field name="note"/>
</tree>
<form string="Email History">
<field name="name"/>
<field name="case_id"/>
<separator colspan="4" string="Notes"/>
<field name="note" nolabel="1" colspan="4"/>
</form>
</field>
</form>
</field>
<field name="reply_to" select="2"/>
</page>
</notebook>
</form>
@ -103,7 +78,7 @@
<field name="view_type">tree</field>
<field name="view_id" ref="crm_case_section_view_tree"/>
</record>
<menuitem action="crm_case_section_act_tree" id="menu_crm_case_section_act_tree" parent="next_id_52"/>
<menuitem action="crm_case_section_act_tree" id="menu_crm_case_section_act_tree" parent="next_id_52"/>
<!-- Case Categories -->
<record id="crm_case_categ-view" model="ir.ui.view">
@ -649,89 +624,5 @@
<act_window domain="[('user_id', '=', active_id),('state','&lt;&gt;','done'),('state','&lt;&gt;','cancel'),('state','&lt;&gt;','pending')]" id="act_res_users_2_crm_case_opened" name="Open cases" res_model="crm.case" src_model="res.users" view_mode="tree,form,calendar" view_type="form"/>
<record id="crm_email_gateway_form" model="ir.ui.view">
<field name="name">crm.email.gateway.form</field>
<field name="model">crm.email.gateway</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Email Gateway">
<field name="name"/>
<field name="section_id" />
<field name="server_id" />
<field name="to_email_id"/>
<field name="cc_email_id" />
<field name="mail_history" widget="one2many_list" nolabel="1" colspan="4">
<tree string="Email History">
<field name="name"/>
<field name="case_id"/>
<field name="note"/>
</tree>
<form string="Email History">
<field name="name"/>
<field name="case_id"/>
<separator colspan="4" string="Notes"/>
<field name="note" nolabel="1" colspan="4"/>
</form>
</field>
</form>
</field>
</record>
<record id="crm_email_gateway_tree" model="ir.ui.view">
<field name="name">crm.email.gateway.tree</field>
<field name="model">crm.email.gateway</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Email Gateway">
<field name="name"/>
<field name="section_id" />
<field name="server_id" />
</tree>
</field>
</record>
<record id="crm_email_gateway_server_form" model="ir.ui.view">
<field name="name">crm.email.gateway.server.form</field>
<field name="model">crm.email.gateway.server</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Email Gateway Server">
<field name="server_type" colspan="4" on_change="onchange_server_type(server_type,ssl)"/>
<field name="name"/>
<field name="port" />
<field name="login" />
<field name="password" password="True"/>
<field name="ssl" on_change="onchange_server_type(server_type,ssl)"/>
<field name="active" />
</form>
</field>
</record>
<record id="crm_email_gateway_server_tree" model="ir.ui.view">
<field name="name">crm.email.gateway.server.tree</field>
<field name="model">crm.email.gateway.server</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Email Gateway Server">
<field name="name"/>
<field name="port" />
<field name="server_type"/>
<field name="ssl" />
</tree>
</field>
</record>
<record id="crm_email_gateway_act" model="ir.actions.act_window">
<field name="name">Email Gateway</field>
<field name="res_model">crm.email.gateway</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="crm_email_gateway_tree"/>
</record>
<menuitem id="crm_email_gateway_menu" name="Email Gateway" parent="next_id_51" action="crm_email_gateway_act" />
</data>
</openerp>

View File

@ -9,18 +9,7 @@
id="wizard_case_history_event"
keyword="client_action_relate"
/>
<wizard string="Fetch mail"
model="crm.case.section"
name="crm.case.section.fetchmail"
id="wizard_crm_case_section_fetchmail"/>
<wizard string="Fetch mail"
model="crm.email.gateway"
name="crm.case.mailgate.fetchmail"
id="wizard_crm_case_mailgateway_fetchmail"/>
/>
</data>
</openerp>

View File

@ -13,12 +13,6 @@
"access_crm_case_rule_manager","crm.case.rule.manager","model_crm_case_rule","crm.group_crm_manager",1,1,1,1
"access_crm_case_log_manager","crm.case.log manager","model_crm_case_log","crm.group_crm_manager",1,1,1,1
"access_crm_case_history_manager","crm.case.history manager","model_crm_case_history","crm.group_crm_manager",1,1,1,1
"access_crm_email_gateway_server_manager","crm.email.gateway.server","model_crm_email_gateway_server","crm.group_crm_manager",1,1,1,1
"access_crm_email_gateway_server_user","crm.email.gateway.server","model_crm_email_gateway_server","crm.group_crm_user",1,0,0,0
"access_crm_email_gateway_manager","crm.email.gateway","model_crm_email_gateway","crm.group_crm_manager",1,1,1,1
"access_crm_email_gateway_user","crm.email.gateway","model_crm_email_gateway","crm.group_crm_user",1,0,0,0
"access_crm_email_history_manager","crm.email.history","model_crm_email_history","crm.group_crm_manager",1,1,1,1
"access_crm_email_history_user","crm.email.history","model_crm_email_history","crm.group_crm_user",1,0,0,0
"access_crm_email_add_cc_manager","crm.email.add.cc","model_crm_email_add_cc","crm.group_crm_manager",1,1,1,1
"access_crm_email_add_cc_user","crm.email.add.cc","model_crm_email_add_cc","crm.group_crm_user",1,0,0,0
"access_crm_case_stage","crm.case.stage","model_crm_case_stage","crm.group_crm_user",1,0,0,0

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
13 access_crm_case_rule_manager crm.case.rule.manager model_crm_case_rule crm.group_crm_manager 1 1 1 1
14 access_crm_case_log_manager crm.case.log manager model_crm_case_log crm.group_crm_manager 1 1 1 1
15 access_crm_case_history_manager crm.case.history manager model_crm_case_history crm.group_crm_manager 1 1 1 1
access_crm_email_gateway_server_manager crm.email.gateway.server model_crm_email_gateway_server crm.group_crm_manager 1 1 1 1
access_crm_email_gateway_server_user crm.email.gateway.server model_crm_email_gateway_server crm.group_crm_user 1 0 0 0
access_crm_email_gateway_manager crm.email.gateway model_crm_email_gateway crm.group_crm_manager 1 1 1 1
access_crm_email_gateway_user crm.email.gateway model_crm_email_gateway crm.group_crm_user 1 0 0 0
access_crm_email_history_manager crm.email.history model_crm_email_history crm.group_crm_manager 1 1 1 1
access_crm_email_history_user crm.email.history model_crm_email_history crm.group_crm_user 1 0 0 0
16 access_crm_email_add_cc_manager crm.email.add.cc model_crm_email_add_cc crm.group_crm_manager 1 1 1 1
17 access_crm_email_add_cc_user crm.email.add.cc model_crm_email_add_cc crm.group_crm_user 1 0 0 0
18 access_crm_case_stage crm.case.stage model_crm_case_stage crm.group_crm_user 1 0 0 0

View File

@ -27,7 +27,6 @@ import crm_phonecall_wizard
import wizard_crm_send_email
import wizard_crm_new_send_email
import wizard_fetch_mail
import wizard_cal_export
import wizard_cal_import
import wizard_cal_subscribe

View File

@ -43,12 +43,19 @@ class crm_project_bug(osv.osv):
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -73,6 +80,30 @@ class crm_project_bug(osv.osv):
return self._map_ids('case_escalate',cr,uid,ids,*args,**argv)
def case_pending(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)

View File

@ -43,12 +43,19 @@ class crm_project_future_request(osv.osv):
}
def _map_ids(self, method, cr, uid, ids, *args, **argv):
case_data = self.browse(cr, uid, ids)
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
case_data = self.browse(cr, uid, select)
new_ids = []
for case in case_data:
if case.inherit_case_id:
new_ids.append(case.inherit_case_id.id)
return getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
res = getattr(self.pool.get('crm.case'),method)(cr, uid, new_ids, *args, **argv)
if isinstance(ids, (str, int, long)) and isinstance(res, list):
return res and res[0] or False
return res
def onchange_case_id(self, cr, uid, ids, *args, **argv):
@ -74,6 +81,30 @@ class crm_project_future_request(osv.osv):
def case_pending(self,cr, uid, ids, *args, **argv):
return self._map_ids('case_pending',cr,uid,ids,*args,**argv)
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'email_from': msg['From'],
'email_cc': msg['Cc'],
'user_id': False,
'description': msg_body['body'],
'history_line': [(0, 0, {'description': msg_body['body'], 'email': msg['From'] })],
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_update',cr, uid, ids, *args, **argv)
def emails_get(self, cr, uid, ids, *args, **argv):
return self._map_ids('emails_get',cr, uid, ids, *args, **argv)
def msg_send(self, cr, uid, ids, *args, **argv):
return self._map_ids('msg_send',cr, uid, ids, *args, **argv)
crm_project_future_request()

View File

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import mail_gateway
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'eMail Gateway',
'version': '1.0',
'category': 'Generic Modules/eMail Gate',
'description': """The generic email gateway system for the synchronisation interface
between mails and Open Objects.
""",
'author': 'Tiny',
'website': 'http://www.openerp.com',
'depends': ['base', 'process'],
'init_xml': ['mail_gateway_data.xml',],
'update_xml': [
'mail_gateway_wizard.xml',
'mail_gateway_view.xml',
'security/ir.model.access.csv',
],
'demo_xml': [],
'installable': True,
'active': False,
'certificate': None,
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,478 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
###########################################################################################
import re
import smtplib
import email, mimetypes
from email.Header import decode_header
from email.MIMEText import MIMEText
import xmlrpclib
import os
import binascii
import time, socket
from tools.translate import _
import tools
from osv import fields,osv,orm
from osv.orm import except_orm
import email
import netsvc
from poplib import POP3, POP3_SSL
from imaplib import IMAP4, IMAP4_SSL
email_re = re.compile(r"""
([a-zA-Z][\w\.-]*[a-zA-Z0-9] # username part
@ # mandatory @ sign
[a-zA-Z0-9][\w\.-]* # domain must start with a letter ... Ged> why do we include a 0-9 then?
\.
[a-z]{2,3} # TLD
)
""", re.VERBOSE)
res_re = re.compile(r"\[([0-9]+)\]", re.UNICODE)
command_re = re.compile("^Set-([a-z]+) *: *(.+)$", re.I + re.UNICODE)
reference_re = re.compile("<.*-openobject-(\\d+)@(.*)>", re.UNICODE)
priorities = {
'1': '1 (Highest)',
'2': '2 (High)',
'3': '3 (Normal)',
'4': '4 (Low)',
'5': '5 (Lowest)',
}
def html2plaintext(html, body_id=None, encoding='utf-8'):
## (c) Fry-IT, www.fry-it.com, 2007
## <peter@fry-it.com>
## download here: http://www.peterbe.com/plog/html2plaintext
""" from an HTML text, convert the HTML to plain text.
If @body_id is provided then this is the tag where the
body (not necessarily <body>) starts.
"""
try:
from BeautifulSoup import BeautifulSoup, SoupStrainer, Comment
except:
return html
urls = []
if body_id is not None:
strainer = SoupStrainer(id=body_id)
else:
strainer = SoupStrainer('body')
soup = BeautifulSoup(html, parseOnlyThese=strainer, fromEncoding=encoding)
for link in soup.findAll('a'):
title = link.renderContents()
for url in [x[1] for x in link.attrs if x[0]=='href']:
urls.append(dict(url=url, tag=str(link), title=title))
html = soup.__str__()
url_index = []
i = 0
for d in urls:
if d['title'] == d['url'] or 'http://'+d['title'] == d['url']:
html = html.replace(d['tag'], d['url'])
else:
i += 1
html = html.replace(d['tag'], '%s [%s]' % (d['title'], i))
url_index.append(d['url'])
html = html.replace('<strong>','*').replace('</strong>','*')
html = html.replace('<b>','*').replace('</b>','*')
html = html.replace('<h3>','*').replace('</h3>','*')
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
html = html.replace('\n',' ')
html = html.replace('<br>', '\n')
html = html.replace('<tr>', '\n')
html = html.replace('</p>', '\n\n')
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)
# lstrip all lines
html = '\n'.join([x.lstrip() for x in html.splitlines()])
for i, url in enumerate(url_index):
if i == 0:
html += '\n\n'
html += '[%s] %s\n' % (i+1, url)
return html
class mail_gateway_server(osv.osv):
_name = "mail.gateway.server"
_description = "Email Gateway Server"
_columns = {
'name': fields.char('Server Address',size=64,required=True ,help="IMAP/POP Address Of Email gateway Server"),
'login': fields.char('User',size=64,required=True,help="User Login Id of Email gateway"),
'password': fields.char('Password',size=64,required=True,help="User Password Of Email gateway"),
'server_type': fields.selection([("pop","POP"),("imap","Imap")],"Type of Server", required=True, help="Type of Email gateway Server"),
'port': fields.integer("Port" , help="Port Of Email gateway Server. If port is omitted, the standard POP3 port (110) is used for POP EMail Server and the standard IMAP4 port (143) is used for IMAP Sever."),
'ssl': fields.boolean('SSL',help ="Use Secure Authentication"),
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the email gateway server without removing it."),
}
_defaults = {
'server_type':lambda * a:'pop',
'active':lambda * a:True,
}
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}}
mail_gateway_server()
class mail_gateway(osv.osv):
_name = "mail.gateway"
_description = "Email Gateway"
_columns = {
'name': fields.char('Name',size=64,help="Name of Mail Gateway."),
'server_id': fields.many2one('mail.gateway.server',"Gateway Server", required=True),
'object_id': fields.many2one('ir.model',"Model", required=True),
'reply_to': fields.char('TO', size=64, help="Email address used in reply to/from of outgoing messages"),
'email_default': fields.char('CC',size=64,help="Default eMail in case of any trouble."),
'mail_history': fields.one2many("mail.gateway.history","gateway_id","History", readonly=True)
}
def _fetch_mails(self, cr, uid, ids=False, context={}):
'''
Function called by the scheduler to fetch mails
'''
cr.execute('select * from mail_gateway gateway \
inner join mail_gateway_server server \
on server.id = gateway.server_id where server.active = True')
ids2 = map(lambda x: x[0], cr.fetchall() or [])
return self.fetch_mails(cr, uid, ids=ids2, context=context)
def parse_mail(self, cr, uid, gateway_id, email_message, context={}):
msg_id, res_id, note = (False, False, False)
mail_history_obj = self.pool.get('mail.gateway.history')
mailgateway = self.browse(cr, uid, gateway_id, context=context)
try :
msg_txt = email.message_from_string(email_message)
msg_id = msg_txt['Message-ID']
res_id = self.msg_parse(cr, uid, gateway_id, msg_txt)
except Exception, e:
note = "Error in Parsing Mail: %s " %(str(e))
if mailgateway:
netsvc.Logger().notifyChannel('Emailgate: Parsing mail:%s' % (mailgateway.name or
'%s (%s)'%(mailgateway.server_id.login, mailgateway.server_id.name)), netsvc.LOG_ERROR, str(e))
mail_history_obj.create(cr, uid, {'name': msg_id, 'res_id': res_id, 'gateway_id': mailgateway.id, 'note': note})
return res_id, note
def fetch_mails(self, cr, uid, ids=[], context={}):
log_messages = []
mailgate_server = False
new_messages = []
for mailgateway in self.browse(cr, uid, ids):
try :
mailgate_server = mailgateway.server_id
if not mailgate_server.active:
continue
mailgate_name = mailgateway.name or "%s (%s)" % (mailgate_server.login, mailgate_server.name)
res_model = mailgateway.object_id.name
log_messages.append("Mail Server : %s" % mailgate_name)
log_messages.append("="*40)
new_messages = []
if mailgate_server.server_type == 'pop':
if mailgate_server.ssl:
pop_server = POP3_SSL(mailgate_server.name or 'localhost', mailgate_server.port or 995)
else:
pop_server = POP3(mailgate_server.name or 'localhost', mailgate_server.port or 110)
pop_server.user(mailgate_server.login)
pop_server.pass_(mailgate_server.password)
pop_server.list()
(numMsgs, totalSize) = pop_server.stat()
for i in range(1, numMsgs + 1):
(header, msges, octets) = pop_server.retr(i)
res_id, note = self.parse_mail(cr, uid, mailgateway.id, '\n'.join(msges))
log = ''
if res_id:
log = _('Object Successfully Created : %d of %s'% (res_id, res_model))
if note:
log = note
log_messages.append(log)
new_messages.append(i)
pop_server.quit()
elif mailgate_server.server_type == 'imap':
if mailgate_server.ssl:
imap_server = IMAP4_SSL(mailgate_server.name or 'localhost', mailgate_server.port or 993)
else:
imap_server = IMAP4(mailgate_server.name or 'localhost', mailgate_server.port or 143)
imap_server.login(mailgate_server.login, mailgate_server.password)
imap_server.select()
typ, data = imap_server.search(None, '(UNSEEN)')
for num in data[0].split():
typ, data = imap_server.fetch(num, '(RFC822)')
res_id, note = self.parse_mail(cr, uid, mailgateway.id, data[0][1])
log = ''
if res_id:
log = _('Object Successfully Created : %d of %s'% (res_id, res_model))
if note:
log = note
log_messages.append(log)
new_messages.append(num)
imap_server.close()
imap_server.logout()
except Exception, e:
log_messages.append("Error in Fetching Mail: %s " %(str(e)))
if mailgate_server:
netsvc.Logger().notifyChannel('Emailgate: Fetching mail:[%d]%s' % (mailgate_server.id, mailgate_server.name), netsvc.LOG_ERROR, str(e))
log_messages.append("-"*25)
log_messages.append("Total Read Mail: %d\n\n" %(len(new_messages)))
return log_messages
def emails_get(self, email_from):
res = email_re.search(email_from)
return res and res.group(1)
def partner_get(self, cr, uid, email):
mail = self.emails_get(email)
adr_ids = self.pool.get('res.partner.address').search(cr, uid, [('email', '=', mail)])
if not adr_ids:
return {}
adr = self.pool.get('res.partner.address').read(cr, uid, adr_ids, ['partner_id'])
res = {}
if len(adr):
res = {
'partner_address_id': adr[0]['id'],
'partner_id': adr[0].get('partner_id',False) and adr[0]['partner_id'][0] or False
}
return res
def _decode_header(self, s):
from email.Header import decode_header
s = decode_header(s)
return ''.join(map(lambda x:x[0].decode(x[1] or 'ascii', 'replace'), s))
def msg_new(self, cr, uid, msg, model):
print ' MSG NEW' , model
message = self.msg_body_get(msg)
res_model = self.pool.get(model)
res_id = res_model.msg_new(cr, uid, msg)
if res_id:
attachments = message['attachment']
for attach in attachments or []:
data_attach = {
'name': str(attach),
'datas':binascii.b2a_base64(str(attachments[attach])),
'datas_fname': str(attach),
'description': 'Mail attachment',
'res_model': model,
'res_id': res_id
}
self.pool.get('ir.attachment').create(cr, uid, data_attach)
return res_id
def msg_body_get(self, msg):
message = {};
message['body'] = '';
message['attachment'] = {};
attachment = message['attachment'];
counter = 1;
def replace(match):
return ''
for part in msg.walk():
if part.get_content_maintype() == 'multipart':
continue
if part.get_content_maintype()=='text':
buf = part.get_payload(decode=True)
if buf:
txt = buf.decode(part.get_charsets()[0] or 'ascii', 'replace')
txt = re.sub("<(\w)>", replace, txt)
txt = re.sub("<\/(\w)>", replace, txt)
if txt and part.get_content_subtype() == 'plain':
message['body'] += txt
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':
filename = part.get_filename();
if filename :
attachment[filename] = part.get_payload(decode=True);
else:
filename = 'attach_file'+str(counter);
counter += 1;
attachment[filename] = part.get_payload(decode=True);
#end if
#end if
message['attachment'] = attachment
#end for
return message
#end def
def msg_update(self, cr, uid, msg, res_id, res_model, user_email):
if user_email and self.emails_get(user_email)==self.emails_get(self._decode_header(msg['From'])):
return self.msg_user(cr, uid, msg, res_id, res_model)
else:
return self.msg_partner(cr, uid, msg, res_id, res_model)
def msg_act_get(self, msg):
body = self.msg_body_get(msg)
# handle email body commands (ex: Set-State: Draft)
actions = {}
body_data = ''
for line in body['body'].split('\n'):
res = command_re.match(line)
if res:
actions[res.group(1).lower()] = res.group(2).lower()
else:
body_data += line+'\n'
return actions, body_data
def msg_user(self, cr, uid, msg, res_id, res_model):
actions, body_data = self.msg_act_get(msg)
if 'user' in actions:
uids = self.pool.get('res.users').name_search(cr, uid, actions['user'])
if uids:
data['user_id'] = uids[0][0]
res_model = self.pool.get(res_model)
return res_model.msg_update(cr, uid, msg, res_id, data=data, default_act='pending')
def msg_send(self, msg, reply_to, emails, priority=None):
if not len(emails):
return False
del msg['To']
msg['To'] = emails[0]
if len(emails)>1:
if 'Cc' in msg:
del msg['Cc']
msg['Cc'] = ','.join(emails[1:])
del msg['Reply-To']
msg['Reply-To'] = reply_to
if priority:
msg['X-Priority'] = priorities.get(priority, '3 (Normal)')
s = smtplib.SMTP()
s.connect()
s.sendmail(reply_to, emails, msg.as_string())
s.close()
return True
def msg_partner(self, cr, uid, msg, res_id, res_model):
res_model = self.pool.get(res_model)
return res_model.msg_update(cr, uid, msg, res_id, data=data, default_act='open')
def msg_parse(self, cr, uid, mailgateway_id, msg):
mailgateway = self.browse(cr, uid, mailgateway_id)
res_model = mailgateway.object_id.model
res_str = reference_re.search(msg.get('References', ''))
if res_str:
res_str = res_str.group(1)
else:
res_str = res_re.search(msg.get('Subject', ''))
if res_str:
res_str = res_str.group(1)
def msg_test(res_str):
emails = ('', '', '', '')
if not res_str:
return (False, emails)
if hasattr(self.pool.get(res_model), 'emails_get'):
emails = self.pool.get(res_model).emails_get(cr, uid, res_str)
return (res_str, emails)
(res_id, emails) = msg_test(res_str)
user_email, from_email, cc_email, priority = emails
if res_id:
self.msg_update(cr, uid, msg, res_id, res_model, user_email)
else:
res_id = self.msg_new(cr, uid, msg, res_model)
subject = self._decode_header(msg['subject'])
if msg.get('Subject', ''):
del msg['Subject']
msg['Subject'] = '[%s] %s' %(str(res_id), subject)
msg['Message-Id'] = '<%s-openobject-%s@%s>'%(str(time.time()), str(res_id), tools.config.get('interface',''))
em = [user_email, from_email] + (cc_email or '').split(',')
emails = map(self.emails_get, filter(None, em))
mm = [self._decode_header(msg['From']), self._decode_header(msg['To'])]+self._decode_header(msg.get('Cc','')).split(',')
msg_mails = map(self.emails_get, filter(None, mm))
emails = filter(lambda m: m and m not in msg_mails, emails)
try:
self.msg_send(msg, mailgateway.reply_to, emails, priority)
if hasattr(self.pool.get(res_model), 'msg_send'):
emails = self.pool.get(res_model).msg_send(cr, uid, res_id)
except Exception, e:
if mailgateway.email_default:
a = self._decode_header(msg['Subject'])
del msg['Subject']
msg['Subject'] = '[OpenERP-CaseError] ' + a
self.msg_send(msg, mailgateway.reply_to, mailgateway.email_default.split(','))
raise e
return res_id
mail_gateway()
class mail_gateway_history(osv.osv):
_name = "mail.gateway.history"
_description = "Mail Gateway History"
_columns = {
'name': fields.char('Message Id', size=64, help="Message Id in Email Server."),
'res_id': fields.integer("Resource ID"),
'gateway_id': fields.many2one('mail.gateway',"Mail Gateway", required=True),
'note': fields.text('Notes'),
}
_order = 'id desc'
mail_gateway_history()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="ir_cron_mail_gateway_action" model="ir.cron">
<field name="name">Check Email (Fetchmail)</field>
<field name="interval_number">5</field>
<field name="interval_type">minutes</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall"/>
<field eval="'mail.gateway'" name="model"/>
<field eval="'_fetch_mails'" name="function"/>
<field eval="'()'" name="args"/>
</record>
</data>
</openerp>

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="mail_gateway_form" model="ir.ui.view">
<field name="name">mail.gateway.form</field>
<field name="model">mail.gateway</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Email Gateway">
<field name="name"/>
<field name="object_id"/>
<field name="server_id" />
<field name="reply_to"/>
<field name="email_default" />
<field name="mail_history" widget="one2many_list" nolabel="1" colspan="4">
<tree string="Email History">
<field name="name"/>
<field name="res_id"/>
</tree>
<form string="Email History">
<field name="name"/>
<field name="res_id"/>
<separator colspan="4" string="Notes"/>
<field name="note" nolabel="1" colspan="4"/>
</form>
</field>
</form>
</field>
</record>
<record id="mail_gateway_tree" model="ir.ui.view">
<field name="name">mail.gateway.tree</field>
<field name="model">mail.gateway</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Email Gateway">
<field name="name"/>
<field name="object_id"/>
<field name="server_id" />
</tree>
</field>
</record>
<record id="mail_gateway_act" model="ir.actions.act_window">
<field name="name">Email Gateway</field>
<field name="res_model">mail.gateway</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="mail_gateway_tree"/>
</record>
<record id="mail_gateway_server_form" model="ir.ui.view">
<field name="name">mail.gateway.server.form</field>
<field name="model">mail.gateway.server</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Email Gateway Server">
<field name="server_type" colspan="4" on_change="onchange_server_type(server_type,ssl)"/>
<field name="name"/>
<field name="port" />
<field name="login" />
<field name="password" password="True"/>
<field name="ssl" on_change="onchange_server_type(server_type,ssl)"/>
<field name="active" />
</form>
</field>
</record>
<record id="mail_gateway_server_tree" model="ir.ui.view">
<field name="name">mail.gateway.server.tree</field>
<field name="model">mail.gateway.server</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Email Gateway Server">
<field name="name"/>
<field name="port" />
<field name="server_type"/>
<field name="ssl" />
</tree>
</field>
</record>
<record id="mail_gateway_server_act" model="ir.actions.act_window">
<field name="name">Email Gateway Server</field>
<field name="res_model">mail.gateway.server</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="mail_gateway_server_tree"/>
</record>
<menuitem id="email_gateway_menu_parent" name="Email Gateway" parent="base.menu_config" />
<menuitem id="email_gateway_menu" parent="email_gateway_menu_parent" action="mail_gateway_act"/>
<menuitem id="email_gateway_server_menu" parent="email_gateway_menu_parent" action="mail_gateway_server_act"/>
</data>
</openerp>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<wizard string="Fetch Mail"
model="mail.gateway"
name="mail_gateway.fetchmail"
id="wizard_mailgateway_fetchmail"/>
</data>
</openerp>

View File

@ -0,0 +1,4 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import wizard_fetch_mail
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,22 +1,21 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 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 General Public License for more details.
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import wizard
@ -47,31 +46,22 @@ _email_done_fields = {
def _default(self , cr, uid, data, context):
pool = pooler.get_pool(cr.dbname)
gateway_pool=pool.get('crm.case.section')
sections = gateway_pool.browse(cr, uid, data['ids'], context=context)
server = []
for section in sections:
for gateway in section.gateway_ids:
if gateway.server_id.active:
server.append(gateway.name or '%s (%s)'%(gateway.server_id.login, gateway.server_id.name) )
gateway_pool=pool.get('mail.gateway')
server = []
for mail_gateway in gateway_pool.browse(cr, uid, data['ids'], context=context):
if mail_gateway.server_id.active:
server.append(mail_gateway.name or '%s (%s)'%(mail_gateway.server_id.login, mail_gateway.server_id.name) )
data['form']['server'] = '\n'.join(server)
return data['form']
def section_fetch_mail(self , cr, uid, data, context):
pool = pooler.get_pool(cr.dbname)
gateway_pool=pool.get('crm.email.gateway')
messages = gateway_pool.fetch_mails(cr, uid, ids=[], section_ids=data['ids'], context=context)
pool = pooler.get_pool(cr.dbname)
gateway_pool=pool.get('mail.gateway')
messages = gateway_pool.fetch_mails(cr, uid, ids=data['ids'], context=context)
data['form']['message'] = '\n'.join(messages)
return data['form']
def mailgate_fetch_mail(self , cr, uid, data, context):
pool = pooler.get_pool(cr.dbname)
gateway_pool=pool.get('crm.email.gateway')
messages = gateway_pool.fetch_mails(cr, uid, ids=data['ids'], context=context)
data['form']['message'] = '\n'.join(messages)
return data['form']
class wiz_section_fetch_mail(wizard.interface):
class wiz_mailgateway_fetch_mail(wizard.interface):
states = {
'init': {
'actions': [_default],
@ -87,22 +77,6 @@ class wiz_section_fetch_mail(wizard.interface):
},
},
}
class wiz_mailgateway_fetch_mail(wizard.interface):
states = {
'init': {
'actions': [],
'result': {'type': 'form', 'arch':_email_form, 'fields':_email_fields, 'state':[('end','Cancel','gtk-cancel'), ('fetch','Fetch','gtk-execute')]}
},
'fetch': {
'actions': [mailgate_fetch_mail],
'result': {'type': 'form', 'arch': _email_done_form,
'fields': _email_done_fields,
'state': (
('end', 'Close'),
)
},
},
}
wiz_section_fetch_mail('crm.case.section.fetchmail')
wiz_mailgateway_fetch_mail('crm.case.mailgate.fetchmail')
wiz_mailgateway_fetch_mail('mail_gateway.fetchmail')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -21,8 +21,10 @@
import project
import company
import project_mailgate
import report
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
import re
import os
import mx.DateTime
import base64
from tools.translate import _
import tools
from osv import fields,osv,orm
from osv.orm import except_orm
class project_tasks(osv.osv):
_name = "project.task"
_inherit = "project.task"
def msg_new(self, cr, uid, msg):
mailgate_obj = self.pool.get('mail.gateway')
msg_body = mailgate_obj.msg_body_get(msg)
data = {
'name': msg['Subject'],
'description': msg_body['body'],
'planned_hours' : 0.0,
'project_id': 1, #TODO : get project id from message
}
res = mailgate_obj.partner_get(cr, uid, msg['From'])
if res:
data.update(res)
res = self.create(cr, uid, data)
return res
def msg_update(self, cr, uid, id, msg, data={}, default_act='pending'):
mailgate_obj = self.pool.get('mail.gateway')
msg_actions, body_data = mailgate_obj.msg_act_get(msg)
data.update({
'description': body_data,
})
act = 'do_'+default_act
if 'state' in msg_actions:
if msg_actions['state'] in ['draft','close','cancel','open','pending']:
act = 'do_' + msg_actions['state']
for k1,k2 in [('cost','planned_hours')]:
try:
data[k2] = float(msg_actions[k1])
except:
pass
if 'priority' in msg_actions:
if msg_actions['priority'] in ('1','2','3','4','5'):
data['priority'] = msg_actions['priority']
self.write(cr, uid, [id], data)
getattr(self,act)(cr, uid, [id])
return True
def emails_get(self, cr, uid, ids, context={}):
res = []
if isinstance(ids, (str, int, long)):
select = [ids]
else:
select = ids
for task in self.browse(cr, uid, select):
user_email = (task.user_id and task.user_id.address_id and task.user_id.address_id.email) or False
res += [(user_email, False, False, task.priority)]
if isinstance(ids, (str, int, long)):
return len(res) and res[0] or False
return res
def msg_send(self, cr, uid, id, *args, **argv):
return True
project_tasks()