'Verify route validity. Check and rules:
1 - if thread_id -> check that document effectively exists; otherwise
fallback on a message_new by resetting thread_id
2 - check that message_update exists if thread_id is set; or at least
that message_new exist
[ - find author_id if udpate_author is set]
3 - if there is an alias, check alias_contact:
\'followers\' and thread_id:
check on target document that the author is in the followers
\'followers\' and alias_parent_thread_id:
check on alias parent document that the author is in the
followers
\'partners\': check that author_id id set
:param message: an email.message instance
:param message_dict: dictionary of values that will be given to
mail_message.create()
:param route: route to check which is a tuple (model, thread_id,
custom_values, uid, alias)
:param update_author: update message_dict[\'author_id\']. TDE TODO: move me
:param assert_model: if an error occurs, tell whether to raise an error
or just log a warning and try other processing or
invalidate route
:param create_fallback: if the route aims at updating a record and that
record does not exists or does not support update
either fallback on creating a new record in the
same model or raise / warn
:param allow_private: allow void model / thread_id routes, aka private
discussions'

@api.model
def message_route_verify(self, message, message_dict, route, update_author=True, assert_model=True, create_fallback=True, allow_private=False, drop_alias=False):

    assert isinstance(route, (list, tuple)), 'A    route    should    be    a    list    or    a    tuple'
    assert (len(route) == 5), 'A    route    should    contain    5    elements:    model,    thread_id,    custom_values,    uid,    alias    record'
    message_id = message.get('Message-Id')
    email_from = tools.decode_message_header(message, 'From')
    author_id = message_dict.get('author_id')
    (model, thread_id, alias) = (route[0], route[1], route[4])
    record_set = None
    _generic_bounce_body_html = ('<div>\n<p>Hello,</p>\n<p>The    following    email    sent    to    %s    cannot    be    accepted    because    this    is    a    private    email    address.\n            Only    allowed    people    can    contact    us    at    this    address.</p>\n</div><blockquote>%s</blockquote>' % (message.get('to'), message_dict.get('body')))
    if (model and (model not in self.env)):
        self._routing_warn((_('unknown    target    model    %s') % model), '', message_id, route, assert_model)
        return ()
    if (not model):
        if thread_id:
            self._routing_warn((_('posting    a    message    without    model    should    be    with    a    null    res_id    (private    message),    received    %s') % thread_id), _('resetting    thread_id'), message_id, route, assert_model)
            thread_id = 0
        if (not message_dict.get('parent_id')):
            self._routing_warn(_('posting    a    message    without    model    should    be    with    a    parent_id    (private    message)'), _('skipping'), message_id, route, assert_model)
            return False
    if (model and thread_id):
        record_set = self.env[model].browse(thread_id)
    elif model:
        record_set = self.env[model]
    if thread_id:
        if ((not record_set.exists()) and create_fallback):
            self._routing_warn((_('reply    to    missing    document    (%s,%s),    fall    back    on    new    document    creation') % (model, thread_id)), '', message_id, route, False)
            thread_id = None
        elif ((not hasattr(record_set, 'message_update')) and create_fallback):
            self._routing_warn((_('model    %s    does    not    accept    document    update,    fall    back    on    document    creation') % model), '', message_id, route, False)
            thread_id = None
        if (not record_set.exists()):
            self._routing_warn((_('reply    to    missing    document    (%s,%s)') % (model, thread_id)), _('skipping'), message_id, route, assert_model)
            return False
        elif (not hasattr(record_set, 'message_update')):
            self._routing_warn((_('model    %s    does    not    accept    document    update') % model), _('skipping'), message_id, route, assert_model)
            return False
    if ((not thread_id) and model and (not hasattr(record_set, 'message_new'))):
        self._routing_warn((_('model    %s    does    not    accept    document    creation') % model), _('skipping'), message_id, route, assert_model)
        return False
    if ((not author_id) and update_author):
        author_ids = self.env['mail.thread']._find_partner_from_emails([email_from], res_model=model, res_id=thread_id)
        if author_ids:
            author_id = author_ids[0]
            message_dict['author_id'] = author_id
    if (alias and (alias.alias_contact == 'followers') and (thread_id or alias.alias_parent_thread_id)):
        if thread_id:
            obj = record_set[0]
        else:
            obj = self.env[alias.alias_parent_model_id.model].browse(alias.alias_parent_thread_id)
        accepted_partner_ids = list((set((partner.id for partner in obj.message_partner_ids)) | set((partner.id for channel in obj.message_channel_ids for partner in channel.channel_partner_ids))))
        if ((not author_id) or (author_id not in accepted_partner_ids)):
            self._routing_warn((_('alias    %s    restricted    to    internal    followers') % alias.alias_name), _('skipping'), message_id, route, False)
            self._routing_create_bounce_email(email_from, _generic_bounce_body_html, message)
            return False
    elif (alias and (alias.alias_contact == 'partners') and (not author_id)):
        self._routing_warn((_('alias    %s    does    not    accept    unknown    author') % alias.alias_name), _('skipping'), message_id, route, False)
        self._routing_create_bounce_email(email_from, _generic_bounce_body_html, message)
        return False
    if ((not model) and (not thread_id) and (not alias) and (not allow_private)):
        return False
    return (model, thread_id, route[2], route[3], (None if drop_alias else route[4]))
