'Access rules of mail.message:
- read: if
- author_id == pid, uid is the author OR
- uid is in the recipients (partner_ids) OR
- uid is member of a listern channel (channel_ids.partner_ids) OR
- uid have read access to the related document if model, res_id
- otherwise: raise
- create: if
- no model, no res_id (private message) OR
- pid in message_follower_ids if model, res_id OR
- uid can read the parent OR
- uid have write or create access on the related document if model, res_id, OR
- otherwise: raise
- write: if
- author_id == pid, uid is the author, OR
- uid is in the recipients (partner_ids) OR
- uid has write or create access on the related document if model, res_id
- otherwise: raise
- unlink: if
- uid has write or create access on the related document if model, res_id
- otherwise: raise
Specific case: non employee users see only messages with subtype (aka do
not see internal logs).'

@api.multi
def check_access_rule(self, operation):

    def _generate_model_record_ids(msg_val, msg_ids):
        "    :param    model_record_ids:    {'model':    {'res_id':    (msg_id,    msg_id)},    ...    }\n                                                                :param    message_values:    {'msg_id':    {'model':    ..,    'res_id':    ..,    'author_id':    ..}}\n                                                "
        model_record_ids = {}
        for id in msg_ids:
            vals = msg_val.get(id, {})
            if (vals.get('model') and vals.get('res_id')):
                model_record_ids.setdefault(vals['model'], set()).add(vals['res_id'])
        return model_record_ids
    if (self._uid == SUPERUSER_ID):
        return
    if (not self.env['res.users'].has_group('base.group_user')):
        self._cr.execute(('SELECT    DISTINCT    message.id,    message.subtype_id,    subtype.internal\n                                                                                                                                FROM    "%s"    AS    message\n                                                                                                                                LEFT    JOIN    "mail_message_subtype"    as    subtype\n                                                                                                                                ON    message.subtype_id    =    subtype.id\n                                                                                                                                WHERE    message.message_type    =    %%s    AND    (message.subtype_id    IS    NULL    OR    subtype.internal    IS    TRUE)    AND    message.id    =    ANY    (%%s)' % self._table), ('comment', self.ids))
        if self._cr.fetchall():
            raise AccessError((_('The    requested    operation    cannot    be    completed    due    to    security    restrictions.    Please    contact    your    system    administrator.\n\n(Document    type:    %s,    Operation:    %s)') % (self._description, operation)))
    message_values = dict(((res_id, {}) for res_id in self.ids))
    if (operation in ['read', 'write']):
        self._cr.execute(('SELECT    DISTINCT    m.id,    m.model,    m.res_id,    m.author_id,    m.parent_id,    partner_rel.res_partner_id,    channel_partner.channel_id    as    channel_id\n                                                                FROM    "%s"    m\n                                                                LEFT    JOIN    "mail_message_res_partner_rel"    partner_rel\n                                                                ON    partner_rel.mail_message_id    =    m.id    AND    partner_rel.res_partner_id    =    (%%s)\n                                                                LEFT    JOIN    "mail_message_mail_channel_rel"    channel_rel\n                                                                ON    channel_rel.mail_message_id    =    m.id\n                                                                LEFT    JOIN    "mail_channel"    channel\n                                                                ON    channel.id    =    channel_rel.mail_channel_id\n                                                                LEFT    JOIN    "mail_channel_partner"    channel_partner\n                                                                ON    channel_partner.channel_id    =    channel.id    AND    channel_partner.partner_id    =    (%%s)\n                                                                WHERE    m.id    =    ANY    (%%s)' % self._table), (self.env.user.partner_id.id, self.env.user.partner_id.id, self.ids))
        for (mid, rmod, rid, author_id, parent_id, partner_id, channel_id) in self._cr.fetchall():
            message_values[mid] = {'model': rmod, 'res_id': rid, 'author_id': author_id, 'parent_id': parent_id, 'notified': any((message_values[mid].get('notified'), partner_id, channel_id))}
    else:
        self._cr.execute(('SELECT    DISTINCT    id,    model,    res_id,    author_id,    parent_id    FROM    "%s"    WHERE    id    =    ANY    (%%s)' % self._table), (self.ids,))
        for (mid, rmod, rid, author_id, parent_id) in self._cr.fetchall():
            message_values[mid] = {'model': rmod, 'res_id': rid, 'author_id': author_id, 'parent_id': parent_id}
    author_ids = []
    if ((operation == 'read') or (operation == 'write')):
        author_ids = [mid for (mid, message) in message_values.iteritems() if (message.get('author_id') and (message.get('author_id') == self.env.user.partner_id.id))]
    elif (operation == 'create'):
        author_ids = [mid for (mid, message) in message_values.iteritems() if ((not message.get('model')) and (not message.get('res_id')))]
    notified_ids = []
    if (operation == 'create'):
        parent_ids = [message.get('parent_id') for (mid, message) in message_values.iteritems() if message.get('parent_id')]
        self._cr.execute(('SELECT    DISTINCT    m.id,    partner_rel.res_partner_id,    channel_partner.partner_id    FROM    "%s"    m\n                                                                LEFT    JOIN    "mail_message_res_partner_rel"    partner_rel\n                                                                ON    partner_rel.mail_message_id    =    m.id    AND    partner_rel.res_partner_id    =    (%%s)\n                                                                LEFT    JOIN    "mail_message_mail_channel_rel"    channel_rel\n                                                                ON    channel_rel.mail_message_id    =    m.id\n                                                                LEFT    JOIN    "mail_channel"    channel\n                                                                ON    channel.id    =    channel_rel.mail_channel_id\n                                                                LEFT    JOIN    "mail_channel_partner"    channel_partner\n                                                                ON    channel_partner.channel_id    =    channel.id    AND    channel_partner.partner_id    =    (%%s)\n                                                                WHERE    m.id    =    ANY    (%%s)' % self._table), (self.env.user.partner_id.id, self.env.user.partner_id.id, parent_ids))
        not_parent_ids = [mid[0] for mid in self._cr.fetchall() if any([mid[1], mid[2]])]
        notified_ids += [mid for (mid, message) in message_values.iteritems() if (message.get('parent_id') in not_parent_ids)]
    other_ids = set(self.ids).difference(set(author_ids), set(notified_ids))
    model_record_ids = _generate_model_record_ids(message_values, other_ids)
    if (operation in ['read', 'write']):
        notified_ids = [mid for (mid, message) in message_values.iteritems() if message.get('notified')]
    elif (operation == 'create'):
        for (doc_model, doc_ids) in model_record_ids.items():
            followers = self.env['mail.followers'].sudo().search([('res_model', '=', doc_model), ('res_id', 'in', list(doc_ids)), ('partner_id', '=', self.env.user.partner_id.id)])
            fol_mids = [follower.res_id for follower in followers]
            notified_ids += [mid for (mid, message) in message_values.iteritems() if ((message.get('model') == doc_model) and (message.get('res_id') in fol_mids))]
    other_ids = other_ids.difference(set(notified_ids))
    model_record_ids = _generate_model_record_ids(message_values, other_ids)
    document_related_ids = []
    for (model, doc_ids) in model_record_ids.items():
        DocumentModel = self.env[model]
        mids = DocumentModel.browse(doc_ids).exists()
        if hasattr(DocumentModel, 'check_mail_message_access'):
            DocumentModel.check_mail_message_access(mids.ids, operation)
        else:
            self.env['mail.thread'].check_mail_message_access(mids.ids, operation, model_name=model)
        document_related_ids += [mid for (mid, message) in message_values.iteritems() if ((message.get('model') == model) and (message.get('res_id') in mids.ids))]
    other_ids = other_ids.difference(set(document_related_ids))
    if (not other_ids):
        return
    raise AccessError((_('The    requested    operation    cannot    be    completed    due    to    security    restrictions.    Please    contact    your    system    administrator.\n\n(Document    type:    %s,    Operation:    %s)') % (self._description, operation)))
