def fromMessage(klass, message, op_endpoint):
        """Construct me from an OpenID message.

        @raises ProtocolError: When not all required parameters are present
            in the message.

        @raises MalformedReturnURL: When the C{return_to} URL is not a URL.

        @raises UntrustedReturnURL: When the C{return_to} URL is outside
            the C{trust_root}.

        @param message: An OpenID checkid_* request Message
        @type message: openid.message.Message

        @param op_endpoint: The endpoint URL of the server that this
            message was sent to.
        @type op_endpoint: str

        @returntype: L{CheckIDRequest}
        """
        self = klass.__new__(klass)
        self.message = message
        self.op_endpoint = op_endpoint
        mode = message.getArg(OPENID_NS, 'mode')
        if mode == "checkid_immediate":
            self.immediate = True
            self.mode = "checkid_immediate"
        else:
            self.immediate = False
            self.mode = "checkid_setup"

        self.return_to = message.getArg(OPENID_NS, 'return_to')
        if message.isOpenID1() and not self.return_to:
            fmt = "Missing required field 'return_to' from %r"
            raise ProtocolError(message, text=fmt % (message,))

        self.identity = message.getArg(OPENID_NS, 'identity')
        self.claimed_id = message.getArg(OPENID_NS, 'claimed_id')
        if message.isOpenID1():
            if self.identity is None:
                s = "OpenID 1 message did not contain openid.identity"
                raise ProtocolError(message, text=s)
        else:
            if self.identity and not self.claimed_id:
                s = ("OpenID 2.0 message contained openid.identity but not "
                     "claimed_id")
                raise ProtocolError(message, text=s)
            elif self.claimed_id and not self.identity:
                s = ("OpenID 2.0 message contained openid.claimed_id but not "
                     "identity")
                raise ProtocolError(message, text=s)

        # There's a case for making self.trust_root be a TrustRoot
        # here.  But if TrustRoot isn't currently part of the "public" API,
        # I'm not sure it's worth doing.

        if message.isOpenID1():
            trust_root_param = 'trust_root'
        else:
            trust_root_param = 'realm'

        # Using 'or' here is slightly different than sending a default
        # argument to getArg, as it will treat no value and an empty
        # string as equivalent.
        self.trust_root = (message.getArg(OPENID_NS, trust_root_param)
                           or self.return_to)

        if not message.isOpenID1():
            if self.return_to is self.trust_root is None:
                raise ProtocolError(message, "openid.realm required when " +
                                    "openid.return_to absent")

        self.assoc_handle = message.getArg(OPENID_NS, 'assoc_handle')

        # Using TrustRoot.parse here is a bit misleading, as we're not
        # parsing return_to as a trust root at all.  However, valid URLs
        # are valid trust roots, so we can use this to get an idea if it
        # is a valid URL.  Not all trust roots are valid return_to URLs,
        # however (particularly ones with wildcards), so this is still a
        # little sketchy.
        if self.return_to is not None and \
               not TrustRoot.parse(self.return_to):
            raise MalformedReturnURL(message, self.return_to)

        # I first thought that checking to see if the return_to is within
        # the trust_root is premature here, a logic-not-decoding thing.  But
        # it was argued that this is really part of data validation.  A
        # request with an invalid trust_root/return_to is broken regardless of
        # application, right?
        if not self.trustRootValid():
            raise UntrustedReturnURL(message, self.return_to, self.trust_root)

        return self
Construct me from an OpenID message.

        @raises ProtocolError: When not all required parameters are present
            in the message.

        @raises MalformedReturnURL: When the C{return_to} URL is not a URL.

        @raises UntrustedReturnURL: When the C{return_to} URL is outside
            the C{trust_root}.

        @param message: An OpenID checkid_* request Message
        @type message: openid.message.Message

        @param op_endpoint: The endpoint URL of the server that this
            message was sent to.
        @type op_endpoint: str

        @returntype: L{CheckIDRequest}