code: func (c *Conversation) receiveUnit(m ValidMessage, forgetFragments bool) (plain MessagePlaintext, toSend []ValidMessage, err error) {
  	message := makeCopy(m)
  	defer wipeBytes(message)
  
  	if !c.Policies.isOTREnabled() {
  		return c.receiveWithoutOTR(message)
  	}
  
  	msgType := guessMessageType(message)
  	var messagesToSend []messageWithHeader
  	shouldForgetFragment := true
  	switch msgType {
  	case msgGuessError:
  		return c.withInjectionsPlain(c.receiveErrorMessage(message))
  	case msgGuessQuery:
  		messagesToSend, err = c.receiveQueryMessage(message)
  	case msgGuessTaggedPlaintext:
  		plain, messagesToSend, err = c.receiveTaggedPlaintext(message)
  	case msgGuessNotOTR:
  		plain, messagesToSend, err = c.receivePlaintext(message)
  	case msgGuessV1KeyExch:
  		return nil, nil, errUnsupportedOTRVersion
  	case msgGuessFragment:
  		shouldForgetFragment = false
  		c.fragmentationContext, err = c.receiveFragment(c.fragmentationContext, message)
  		if fragmentsFinished(c.fragmentationContext) {
  			return c.withInjectionsPlain(c.receiveUnit(c.fragmentationContext.frag, false))
  		}
  	case msgGuessUnknown:
  		c.messageEvent(MessageEventReceivedMessageUnrecognized)
  	case msgGuessDHCommit, msgGuessDHKey, msgGuessRevealSig, msgGuessSignature, msgGuessData:
  		plain, messagesToSend, err = c.receiveEncoded(encodedMessage(message))
  	}
  
  	if shouldForgetFragment && forgetFragments {
  		c.fragmentationContext = forgetFragment()
  	}
  
  	return c.withInjectionsPlain(c.toSendEncoded(plain, messagesToSend, err))
  }
docs: // Receive handles a message from a peer. It returns a human readable message and zero or more messages to send back to the peer.