/*
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * Copyright (c) 1999-2001 Apple Computer, Inc.  All Rights Reserved. The
 * contents of this file constitute Original Code as defined in and are
 * subject to the Apple Public Source License Version 1.2 (the 'License').
 * You may not use this file except in compliance with the License.  Please
 * obtain a copy of the License at http://www.apple.com/publicsource and
 * read it before using this file.
 *
 * This Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.  Please
 * see the License for the specific language governing rights and
 * limitations under the License.
 *
 *
 * @APPLE_LICENSE_HEADER_END@
 *
 */
/*
	File:		RTSPProtocol.cpp

	Contains:	Implementation of class defined in RTSPProtocol.h

*/

#include <ctype.h>
#include "RTSPProtocol.h"

StrPtrLen RTSPProtocol::sRetrProtName("our-retransmit");

StrPtrLen RTSPProtocol::sMethods[] =
{
	StrPtrLen("DESCRIBE"),
	StrPtrLen("SETUP"),
	StrPtrLen("TEARDOWN"),
	StrPtrLen("PLAY"),
	StrPtrLen("PAUSE"),
	StrPtrLen("OPTIONS"),
	StrPtrLen("ANNOUNCE"),
	StrPtrLen("GET_PARAMETER"),
	StrPtrLen("SET_PARAMETER"),
	StrPtrLen("REDIRECT"),
	StrPtrLen("RECORD")
};

QTSS_RTSPMethod
RTSPProtocol::GetMethod(const StrPtrLen &inMethodStr)
{
	//chances are this is one of our selected "VIP" methods. so check for this.
	QTSS_RTSPMethod theMethod = qtssIllegalMethod;
	
	switch(*inMethodStr.Ptr)
	{
		case 'S': 	case 's':	theMethod = qtssSetupMethod;	break;
		case 'D':	case 'd':	theMethod = qtssDescribeMethod;	break;
		case 'T':	case 't':	theMethod = qtssTeardownMethod;	break;
		case 'O':	case 'o':	theMethod = qtssOptionsMethod;	break;
		case 'A':	case 'a':	theMethod = qtssAnnounceMethod;	break;
	}

	if ((theMethod != qtssIllegalMethod) &&
		(inMethodStr.EqualIgnoreCase(sMethods[theMethod].Ptr, sMethods[theMethod].Len)))
		return theMethod;

	for (SInt32 x = qtssNumVIPMethods; x < qtssIllegalMethod; x++)
		if (inMethodStr.EqualIgnoreCase(sMethods[x].Ptr, sMethods[x].Len))
			return x;
	return qtssIllegalMethod;
}


StrPtrLen RTSPProtocol::sHeaders[] =
{
	StrPtrLen("Accept"),
	StrPtrLen("Cseq"),
	StrPtrLen("User-Agent"),
	StrPtrLen("Transport"),
	StrPtrLen("Session"),
	StrPtrLen("Range"),

	StrPtrLen("Accept-Encoding"),
	StrPtrLen("Accept-Language"),
	StrPtrLen("Authorization"),
	StrPtrLen("Bandwidth"),
	StrPtrLen("Blocksize"),
	StrPtrLen("Cache-Control"),
	StrPtrLen("Conference"),
	StrPtrLen("Connection"),
	StrPtrLen("Content-Base"),
	StrPtrLen("Content-Encoding"),
	StrPtrLen("Content-Language"),
	StrPtrLen("Content-length"),
	StrPtrLen("Content-Location"),
	StrPtrLen("Content-Type"),
	StrPtrLen("Date"),
	StrPtrLen("Expires"),
	StrPtrLen("From"),
	StrPtrLen("Host"),
	StrPtrLen("If-Match"),
	StrPtrLen("If-Modified-Since"),
	StrPtrLen("Last-Modified"),
	StrPtrLen("Location"),
	StrPtrLen("Proxy-Authenticate"),
	StrPtrLen("Proxy-Require"),
	StrPtrLen("Referer"),
	StrPtrLen("Retry-After"),
	StrPtrLen("Require"),
	StrPtrLen("RTP-Info"),
	StrPtrLen("Scale"),
	StrPtrLen("Speed"),
	StrPtrLen("Timestamp"),
	StrPtrLen("Vary"),
	StrPtrLen("Via"),
	StrPtrLen("Allow"),
	StrPtrLen("Public"),
	StrPtrLen("Server"),
	StrPtrLen("Unsupported"),
	StrPtrLen("WWW-Authenticate"),
	StrPtrLen(","),
	StrPtrLen("x-Retransmit"),
	StrPtrLen("x-Accept-Retransmit"),
	StrPtrLen("x-RTP-Meta-Info"),
	StrPtrLen("x-Transport-Options"),
	StrPtrLen("x-Packet-Range"),
	StrPtrLen("x-Prebuffer"),
	StrPtrLen("x-Dynamic-Rate"),
	StrPtrLen("x-Accept-Dynamic-Rate")
};

QTSS_RTSPHeader	RTSPProtocol::GetRequestHeader(const StrPtrLen &inHeaderStr)
{
	if (inHeaderStr.Len == 0)
		return qtssIllegalHeader;
	
	QTSS_RTSPHeader theHeader = qtssIllegalHeader;
	
	//chances are this is one of our selected "VIP" headers. so check for this.
	switch(*inHeaderStr.Ptr)
	{
		case 'C': 	case 'c':	theHeader = qtssCSeqHeader;			break;
		case 'S':	case 's':	theHeader = qtssSessionHeader;		break;
		case 'U':	case 'u':	theHeader = qtssUserAgentHeader;	break;
		case 'A':	case 'a':	theHeader = qtssAcceptHeader;		break;
		case 'T':	case 't':	theHeader = qtssTransportHeader;	break;
		case 'R':	case 'r':	theHeader = qtssRangeHeader;		break;
		case 'X':	case 'x':	theHeader = qtssExtensionHeaders;	break;
	}
	
	//
	// Check to see whether this is one of our extension headers. These
	// are very likely to appear in requests.
	if (theHeader == qtssExtensionHeaders)
	{
		for (SInt32 y = qtssExtensionHeaders; y < qtssNumHeaders; y++)
		{
			if (inHeaderStr.EqualIgnoreCase(sHeaders[y].Ptr, sHeaders[y].Len))
				return y;
		}
	}
	
	//
	// It's not one of our extension headers, check to see if this is one of
	// our normal VIP headers
	if ((theHeader != qtssIllegalHeader) &&
		(inHeaderStr.EqualIgnoreCase(sHeaders[theHeader].Ptr, sHeaders[theHeader].Len)))
		return theHeader;

	//
	//If this isn't one of our VIP headers, go through the remaining request headers, trying
	//to find the right one.
	for (SInt32 x = qtssNumVIPHeaders; x < qtssNumHeaders; x++)
	{
		if (inHeaderStr.EqualIgnoreCase(sHeaders[x].Ptr, sHeaders[x].Len))
			return x;
	}
	return qtssIllegalHeader;
}



StrPtrLen RTSPProtocol::sStatusCodeStrings[] =
{
	StrPtrLen("Continue"),								//kContinue
	StrPtrLen("OK"),									//kSuccessOK
	StrPtrLen("Created"),								//kSuccessCreated
	StrPtrLen("Accepted"),								//kSuccessAccepted
	StrPtrLen("No Content"),							//kSuccessNoContent
	StrPtrLen("Partial Content"),						//kSuccessPartialContent
	StrPtrLen("Low on Storage Space"),					//kSuccessLowOnStorage
	StrPtrLen("Multiple Choices"),						//kMultipleChoices
	StrPtrLen("Moved Permanently"),						//kRedirectPermMoved
	StrPtrLen("Found"),									//kRedirectTempMoved
	StrPtrLen("See Other"),								//kRedirectSeeOther
	StrPtrLen("Not Modified"),							//kRedirectNotModified
	StrPtrLen("Use Proxy"),								//kUseProxy
	StrPtrLen("Bad Request"),							//kClientBadRequest
	StrPtrLen("Unauthorized"),							//kClientUnAuthorized
	StrPtrLen("Payment Required"),						//kPaymentRequired
	StrPtrLen("Forbidden"),								//kClientForbidden
	StrPtrLen("Not Found"),								//kClientNotFound
	StrPtrLen("Method Not Allowed"),					//kClientMethodNotAllowed
	StrPtrLen("Not Acceptable"),						//kNotAcceptable
	StrPtrLen("Proxy Authentication Required"),			//kProxyAuthenticationRequired
	StrPtrLen("Request Time-out"),						//kRequestTimeout
	StrPtrLen("Conflict"),								//kClientConflict
	StrPtrLen("Gone"),									//kGone
	StrPtrLen("Length Required"),						//kLengthRequired
	StrPtrLen("Precondition Failed"),					//kPreconditionFailed
	StrPtrLen("Request Entity Too Large"),				//kRequestEntityTooLarge
	StrPtrLen("Request-URI Too Large"),					//kRequestURITooLarge
	StrPtrLen("Unsupported Media Type"),				//kUnsupportedMediaType
	StrPtrLen("Parameter Not Understood"),				//kClientParameterNotUnderstood
	StrPtrLen("Conference Not Found"),					//kClientConferenceNotFound
	StrPtrLen("Not Enough Bandwidth"),					//kClientNotEnoughBandwidth
	StrPtrLen("Session Not Found"),						//kClientSessionNotFound
	StrPtrLen("Method Not Valid in this State"),		//kClientMethodNotValidInState
	StrPtrLen("Header Field Not Valid For Resource"),	//kClientHeaderFieldNotValid
	StrPtrLen("Invalid Range"),							//kClientInvalidRange
	StrPtrLen("Parameter Is Read-Only"),				//kClientReadOnlyParameter
	StrPtrLen("Aggregate Option Not Allowed"),			//kClientAggregateOptionNotAllowed
	StrPtrLen("Only Aggregate Option Allowed"),			//kClientAggregateOptionAllowed
	StrPtrLen("Unsupported Transport"),					//kClientUnsupportedTransport
	StrPtrLen("Destination Unreachable"),				//kClientDestinationUnreachable
	StrPtrLen("Internal Server Error"),					//kServerInternal
	StrPtrLen("Not Implemented"),						//kServerNotImplemented
	StrPtrLen("Bad Gateway"),							//kServerBadGateway
	StrPtrLen("Service Unavailable"),					//kServerUnavailable
	StrPtrLen("Gateway Timeout"),						//kServerGatewayTimeout
	StrPtrLen("RTSP Version not supported"),			//kRTSPVersionNotSupported
	StrPtrLen("Option Not Supported")					//kServerOptionNotSupported
};

SInt32 RTSPProtocol::sStatusCodes[] =
{
 	100,		//kContinue
 	200,		//kSuccessOK
 	201,		//kSuccessCreated
 	202,		//kSuccessAccepted
 	204,		//kSuccessNoContent
 	206,		//kSuccessPartialContent
 	250,		//kSuccessLowOnStorage
 	300,		//kMultipleChoices
	301,		//kRedirectPermMoved
 	302,		//kRedirectTempMoved
 	303,		//kRedirectSeeOther
 	304,		//kRedirectNotModified
 	305,		//kUseProxy
 	400,		//kClientBadRequest
 	401,		//kClientUnAuthorized
 	402,		//kPaymentRequired
 	403,		//kClientForbidden
 	404,		//kClientNotFound
 	405,		//kClientMethodNotAllowed
 	406,		//kNotAcceptable
 	407,		//kProxyAuthenticationRequired
 	408,		//kRequestTimeout
 	409,		//kClientConflict
 	410,		//kGone
 	411,		//kLengthRequired
 	412,		//kPreconditionFailed
 	413,		//kRequestEntityTooLarge
 	414,		//kRequestURITooLarge
 	415,		//kUnsupportedMediaType
 	451,		//kClientParameterNotUnderstood
 	452,		//kClientConferenceNotFound
 	453,		//kClientNotEnoughBandwidth
 	454,		//kClientSessionNotFound
 	455,		//kClientMethodNotValidInState
 	456,		//kClientHeaderFieldNotValid
 	457,		//kClientInvalidRange
 	458,		//kClientReadOnlyParameter
 	459,		//kClientAggregateOptionNotAllowed
 	460,		//kClientAggregateOptionAllowed
 	461,		//kClientUnsupportedTransport
 	462,		//kClientDestinationUnreachable
 	500,		//kServerInternal
 	501,		//kServerNotImplemented
 	502,		//kServerBadGateway
 	503,		//kServerUnavailable
 	504,		//kServerGatewayTimeout
 	505,		//kRTSPVersionNotSupported
 	551			//kServerOptionNotSupported
};

StrPtrLen RTSPProtocol::sStatusCodeAsStrings[] =
{
 	StrPtrLen("100"),		//kContinue
 	StrPtrLen("200"),		//kSuccessOK
 	StrPtrLen("201"),		//kSuccessCreated
 	StrPtrLen("202"),		//kSuccessAccepted
 	StrPtrLen("204"),		//kSuccessNoContent
 	StrPtrLen("206"),		//kSuccessPartialContent
 	StrPtrLen("250"),		//kSuccessLowOnStorage
 	StrPtrLen("300"),		//kMultipleChoices
	StrPtrLen("301"),		//kRedirectPermMoved
 	StrPtrLen("302"),		//kRedirectTempMoved
 	StrPtrLen("303"),		//kRedirectSeeOther
 	StrPtrLen("304"),		//kRedirectNotModified
 	StrPtrLen("305"),		//kUseProxy
 	StrPtrLen("400"),		//kClientBadRequest
 	StrPtrLen("401"),		//kClientUnAuthorized
 	StrPtrLen("402"),		//kPaymentRequired
 	StrPtrLen("403"),		//kClientForbidden
 	StrPtrLen("404"),		//kClientNotFound
 	StrPtrLen("405"),		//kClientMethodNotAllowed
 	StrPtrLen("406"),		//kNotAcceptable
 	StrPtrLen("407"),		//kProxyAuthenticationRequired
 	StrPtrLen("408"),		//kRequestTimeout
 	StrPtrLen("409"),		//kClientConflict
 	StrPtrLen("410"),		//kGone
 	StrPtrLen("411"),		//kLengthRequired
 	StrPtrLen("412"),		//kPreconditionFailed
 	StrPtrLen("413"),		//kRequestEntityTooLarge
 	StrPtrLen("414"),		//kRequestURITooLarge
 	StrPtrLen("415"),		//kUnsupportedMediaType
 	StrPtrLen("451"),		//kClientParameterNotUnderstood
 	StrPtrLen("452"),		//kClientConferenceNotFound
 	StrPtrLen("453"),		//kClientNotEnoughBandwidth
 	StrPtrLen("454"),		//kClientSessionNotFound
 	StrPtrLen("455"),		//kClientMethodNotValidInState
 	StrPtrLen("456"),		//kClientHeaderFieldNotValid
 	StrPtrLen("457"),		//kClientInvalidRange
 	StrPtrLen("458"),		//kClientReadOnlyParameter
 	StrPtrLen("459"),		//kClientAggregateOptionNotAllowed
 	StrPtrLen("460"),		//kClientAggregateOptionAllowed
 	StrPtrLen("461"),		//kClientUnsupportedTransport
 	StrPtrLen("462"),		//kClientDestinationUnreachable
 	StrPtrLen("500"),		//kServerInternal
 	StrPtrLen("501"),		//kServerNotImplemented
 	StrPtrLen("502"),		//kServerBadGateway
 	StrPtrLen("503"),		//kServerUnavailable
 	StrPtrLen("504"),		//kServerGatewayTimeout
 	StrPtrLen("505"),		//kRTSPVersionNotSupported
 	StrPtrLen("551")		//kServerOptionNotSupported
};

StrPtrLen RTSPProtocol::sVersionString[] = 
{
	StrPtrLen("RTSP/1.0")
};

RTSPProtocol::RTSPVersion
RTSPProtocol::GetVersion(StrPtrLen &versionStr)
{
	if (versionStr.Len != 8)
		return kIllegalVersion;
	else
		return k10Version;
}
