docs: def process_action(self, raw_user, channel, raw_message):
          """Called when a message is received from a channel or user."""
          log.info("%s %s %s", channel, raw_user, raw_message)
  
          if not raw_user:
              # ignore server messages
              return
  
          # This monster of a regex extracts msg and target from a message, where
          # the target may not be there, and the target is a valid irc name.
          # Valid ways to target someone are "<nick>: ..." and "<nick>, ..."
          target, message = re.match(
              r'^(?:([a-z_\-\[\]\\^{}|`]'  # First letter can't be a number
              '[a-z0-9_\-\[\]\\^{}|`]*)'   # The rest can be many things
              '[:,] )? *(.*)$',            # The actual message
              raw_message, re.I).groups()
  
          pm = channel == self.nickname
          if pm:
              directed = True
          if target:
              if target.lower() == self.nickname.lower():
                  directed = True
              else:
                  directed = False
                  message = '{0}: {1}'.format(target, message)
          else:
              directed = False
          if message.startswith('!'):
              message = message[1:]
              directed = True
  
          if directed:
              message = message.rstrip()
  
          try:
              user, mask = raw_user.split('!', 1)
          except ValueError:
              user = raw_user
              mask = ''
  
          comm = {
              'raw_message': raw_message,
              'message': message,
              'raw_user': raw_user,
              'user': user,
              'mask': mask,
              'target': target,
              'channel': channel,
              'directed': directed,
              'pm': pm,
          }
  
          self.dispatch('chat', 'message', comm)
  
          self.factory.history.setdefault(
              channel, deque(maxlen=100)).append(comm)