'Search the message database for particular messages. At least
one of the arguments must be given to do a search.
Args:
sender (Object or Player, optional): Get messages sent by a particular player or object
receiver (Object, Player or Channel, optional): Get messages
received by a certain player,object or channel
freetext (str): Search for a text string in a message.  NOTE:
This can potentially be slow, so make sure to supply one of
the other arguments to limit the search.
dbref (int): The exact database id of the message. This will override
all other search criteria since it\'s unique and
always gives only one match.
Returns:
messages (list or Msg): A list of message matches or a single match if `dbref` was given.'

def search_message(self, sender=None, receiver=None, freetext=None, dbref=None):

    if dbref:
        msg = self.objects.filter(id=dbref)
        if msg:
            return msg[0]
    (sender, styp) = identify_object(sender)
    if (styp == 'player'):
        sender_restrict = (Q(db_sender_players=sender) & (~ Q(db_hide_from_players=sender)))
    elif (styp == 'object'):
        sender_restrict = (Q(db_sender_objects=sender) & (~ Q(db_hide_from_objects=sender)))
    else:
        sender_restrict = Q()
    (receiver, rtyp) = identify_object(receiver)
    if (rtyp == 'player'):
        receiver_restrict = (Q(db_receivers_players=receiver) & (~ Q(db_hide_from_players=receiver)))
    elif (rtyp == 'object'):
        receiver_restrict = (Q(db_receivers_objects=receiver) & (~ Q(db_hide_from_objects=receiver)))
    elif (rtyp == 'channel'):
        receiver_restrict = (Q(db_receivers_channels=receiver) & (~ Q(db_hide_from_channels=receiver)))
    else:
        receiver_restrict = Q()
    if freetext:
        fulltext_restrict = (Q(db_header__icontains=freetext) | Q(db_message__icontains=freetext))
    else:
        fulltext_restrict = Q()
    return list(self.filter(((sender_restrict & receiver_restrict) & fulltext_restrict)))
