Index: configure.ac
===================================================================
RCS file: /cvsroot/curl/curl/configure.ac,v
retrieving revision 1.446
diff -u -p -r1.446 configure.ac
--- configure.ac	13 Jan 2010 01:13:23 -0000	1.446
+++ configure.ac	14 Jan 2010 18:18:22 -0000
@@ -135,6 +135,7 @@ curl_verbose_msg="enabled (--disable-ver
    curl_sspi_msg="no      (--enable-sspi)"
    curl_ldap_msg="no      (--enable-ldap / --with-ldap-lib / --with-lber-lib)"
   curl_ldaps_msg="no      (--enable-ldaps)"
+  curl_rtsp_msg="no       (--enable-rtsp)"
 
 dnl
 dnl Save anything in $LIBS for later
@@ -416,6 +417,28 @@ AC_HELP_STRING([--disable-ldaps],[Disabl
        AC_SUBST(CURL_DISABLE_LDAPS, [1])
 )
 
+AC_MSG_CHECKING([whether to support rtsp])
+AC_ARG_ENABLE(rtsp,
+AC_HELP_STRING([--enable-rtsp],[Enable RTSP support])
+AC_HELP_STRING([--disable-rtsp],[Disable RTSP support]),
+[ case "$enableval" in
+  no)
+       AC_MSG_RESULT(no)
+       AC_DEFINE(CURL_DISABLE_RTSP, 1, [to disable RTSP])
+       AC_SUBST(CURL_DISABLE_RTSP, [1])
+       ;;
+       *)   if test x$CURL_DISABLE_HTTP = x1 ; then
+                    AC_MSG_ERROR(HTTP support needs to be enabled in order to enable RTSP support!)
+            else
+                    AC_MSG_RESULT(yes)
+                    curl_rtsp_msg="enabled"
+            fi
+       ;;
+  esac ],
+       AC_MSG_RESULT(no)
+       curl_rtsp_msg="disabled"
+)
+
 AC_MSG_CHECKING([whether to support proxies])
 AC_ARG_ENABLE(proxy,
 AC_HELP_STRING([--enable-proxy],[Enable proxy support])
@@ -2580,6 +2603,9 @@ if test "x$USE_LIBSSH2" = "x1"; then
   SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SCP"
   SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS SFTP"
 fi
+if test "x$CURL_DISABLE_RTSP" != "x1"; then
+  SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS RTSP"
+fi
 
 AC_SUBST(SUPPORT_PROTOCOLS)
 
@@ -2654,6 +2680,7 @@ AC_MSG_NOTICE([Configured to build curl/
   ca cert path:    ${capath}
   LDAP support:    ${curl_ldap_msg}
   LDAPS support:   ${curl_ldaps_msg}
+  RTSP support:    ${curl_rtsp_msg}
   Protocols:       ${SUPPORT_PROTOCOLS}
 ])
 
Index: docs/libcurl/curl_easy_getinfo.3
===================================================================
RCS file: /cvsroot/curl/curl/docs/libcurl/curl_easy_getinfo.3,v
retrieving revision 1.43
diff -u -p -r1.43 curl_easy_getinfo.3
--- docs/libcurl/curl_easy_getinfo.3	15 Jul 2009 11:49:13 -0000	1.43
+++ docs/libcurl/curl_easy_getinfo.3	14 Jan 2010 18:18:23 -0000
@@ -209,6 +209,28 @@ the previous request didn't match (see \
 this returns a 1 you know that the reason you didn't get data in return is
 because it didn't fulfill the condition. The long ths argument points to will
 get a zero stored if the condition instead was met. (Added in 7.19.4)
+.IP CURLINFO_RTSP_SESSION_ID
+Pass a pointer to a char pointer to receive a pointer to a string holding the
+most recent RTSP Session ID.
+
+Applications wishing to resume an RTSP session on another connection should
+retreive this info before closing the active connection.
+.IP CURLINFO_RTSP_CLIENT_CSEQ
+Pass a pointer to a long to receive the next CSeq that will be used by the
+application. 
+.IP CURLINFO_RTSP_SERVER_CSEQ
+Pass a pointer to a long to receive the next server CSeq that will be expected
+by the application. 
+
+\fI(NOTE: listening for server initiated requests is currently
+unimplemented).\fP
+
+Applications wishing to resume an RTSP session on another connection should
+retreive this info before closing the active connection.
+.IP CURLINFO_RTSP_CSEQ_RECV
+Pass a pointer to a long to receive the most recently received CSeq from the
+server. If your application encounters a \fICURLE_RTSP_CSEQ_ERROR\fP then you
+may wish to troubleshoot and/or fix the CSeq mismatch by peeking at this value.
 .SH TIMES
 .nf
 An overview of the six time values available from curl_easy_getinfo()
Index: docs/libcurl/curl_easy_setopt.3
===================================================================
RCS file: /cvsroot/curl/curl/docs/libcurl/curl_easy_setopt.3,v
retrieving revision 1.271
diff -u -p -r1.271 curl_easy_setopt.3
--- docs/libcurl/curl_easy_setopt.3	6 Jan 2010 16:01:48 -0000	1.271
+++ docs/libcurl/curl_easy_setopt.3	14 Jan 2010 18:18:24 -0000
@@ -1275,6 +1275,145 @@ file \&"normally" (like in the multicwd 
 compliant than 'nocwd' but without the full penalty of 'multicwd'.
 .RE
 (Added in 7.15.1)
+.SH RTSP OPTIONS
+.IP CURLOPT_RTSP_REQUEST
+Tell libcurl what kind of RTSP request to make. Pass one of the following RTSP
+enum values. Unless noted otherwise, commands require the Session ID to be
+initialized. (Added in 7.20.x)
+.RS
+.IP CURL_RTSPREQ_OPTIONS
+Used to retrieve the available methods of the server. The application is
+responsbile for parsing and obeying the response. \fB(The session ID is not
+needed for this method.)\fP  (Added in 7.20.x)
+.IP CURL_RTSPREQ_DESCRIBE
+Used to get the low level description of a stream. The application should note
+what formats it understands in the \fI'Accept:'\fP header. Unless set
+manually, libcurl will automatically fill in \fI'Accept:
+application/sdp'\fP. Time-condition headers will be added to Describe requests
+if the \fICURLOPT_TIMECONDITION\fP option is active. \fB(The session ID is not
+needed for this method)\fP  (Added in 7.20.x)
+.IP CURL_RTSPREQ_ANNOUNCE
+When sent by a client, this method changes the description of the session. For
+example, if a client is using the server to record a meeting, the client can
+use Announce to inform the server of all the meta-information about the
+session.  ANNOUNCE acts like an HTTP PUT or POST just like
+\fICURL_RTSPREQ_SET_PARAMETER\fP (Added in 7.20.x)
+.IP CURL_RTSPREQ_SETUP
+Setup is used to initialize the transport layer for the session. The
+application must set the desired Transport options for a session by using the
+\fICURLOPT_RTSP_TRANSPORT\fP option prior to calling setup. If no session ID
+is currently set with \fICURLOPT_RTSP_SESSION_ID\fP, libcurl will extract and
+use the session ID in the response to this request. \fB(The session ID is not
+needed for this method).\fP  (Added in 7.20.x)
+.IP CURL_RTSPREQ_PLAY
+Send a Play command to the server. Use the \fICURLOPT_RANGE\fP option to
+modify the playback time (e.g. 'npt=10-15').  (Added in 7.20.x)
+.IP CURL_RTSPREQ_PAUSE
+Send a Pause command to the server. Use the \fICURLOPT_RANGE\fP option with a
+single value to indicate when the stream should be halted. (e.g. npt='25')
+(Added in 7.20.x)
+.IP CURL_RTSPREQ_TEARDOWN
+This command terminates an RTSP session. Note that simply closing a connection
+does not terminate the RTSP session since it is valid to control an RTSP
+session over different connections.  (Added in 7.20.x)
+.IP CURL_RTSPREQ_GET_PARAMETER
+Retrieve a parameter from the server. By default, libcurl will automatically
+include an \fIAccept: text/parameters\fP header unless a custom one is set.
+Applications wishing to send a heartbeat message (e.g. in the presence of a
+server-specified timeout) should send use an empty GET_PARAMETER request.
+(Added in 7.20.x)
+.IP CURL_RTSPREQ_SET_PARAMETER
+Set a parameter on the server. By default, libcurl will automatically include
+a \fIContent-Type: text/parameters\fP header unless a custom one is set. The
+interaction with SET_PARAMTER is much like an HTTP PUT or POST. An application
+may either use \fICURLOPT_UPLOAD\fP with \fICURLOPT_READDATA\fP like an HTTP
+PUT, or it may use \fICURLOPT_POSTFIELDS\fP like an HTTP POST. Note that no
+chunked transfers are allowed, so the application must set the
+\fICURLOPT_INFILESIZE\fP in the former and \fICURLOPT_POSTFIELDSIZE\fP in the
+latter. Also, there is no use of multi-part POSTs within RTSP. (Added in
+7.20.x)
+.IP CURL_RTSPREQ_RECORD
+Used to tell the server to record a session. Use the \fICURLOPT_RANGE\fP
+option to modify the record time. (Added in 7.20.x)
+.IP CURL_RTSPREQ_RECEIVE
+This is a special request because it does not send any data to the server. The
+application may call this function in order to receive interleaved RTP
+data. It will return after processing one read buffer of data in order to give
+the application a chance to run. (Added in 7.20.x)
+.RE
+.IP CURLOPT_RTSP_SESSION_ID
+Pass a char * as a parameter to set the value of the current RTSP Session ID
+for the handle. Useful for resuming an in-progress session. Once this value is
+set to any non-NULL value, libcurl will return \fICURLE_RTSP_SESSION_ERROR\fP
+if ID received from the server does not match. If unset (or set to NULL),
+libcurl will automatically set the ID the first time the server sets it in a
+response. (Added in 7.20.x)
+.IP CURLOPT_RTSP_STREAM_URI
+Set the stream URI to operate on by passing a char * . For example, a single
+session may be controlling \fIrtsp://foo/twister/audio\fP and
+\fIrtsp://foo/twister/video\fP and the application can switch to the
+appropriate stream using this option. If unset, libcurl will default to
+operating on generic server options by passing '*' in the place of the RTSP
+Stream URI. Note that this option is distinct from \fICURLOPT_URL\fP. When
+working with RTSP, the \fICURLOPT_STREAM_URI\fP indicates what URL to send to
+the server in the request header while the \fICURLOPT_URL\fP indicates where
+to make the connection to.  (e.g. the \fICURLOPT_URL\fP for the above examples
+might be set to \fIrtsp://foo/twister\fP (Added in 7.20.x)
+.IP CURLOPT_RTSP_TRANSPORT
+Pass a char * to tell libcurl what to pass for the Transport: header for this
+RTSP session. This is mainly a convenience method to avoid needing to set a
+custom Transport: header for every SETUP request. The application must set a
+Transport: header before issuing a SETUP request. (Added in 7.20.x)
+.IP CURLOPT_RTSP_VERSION
+Currently, there is only one version of the RTSP protocol (1.0). So at the
+moment, this option is inactive. Its function is similar to the
+\fICURLOPT_HTTP_VERSION\fP. (Added in 7.20.x)
+.IP CURLOPT_RTSP_HEADER
+This option is simply an alias for \fICURLOPT_HTTP_HEADER\fP. Use this to
+replace the standard headers that RTSP and HTTP share. It is also valid to use
+the shortcuts such as \fICURLOPT_USERAGENT\fP. (Added in 7.20.x)
+.RS
+.IP CURL_RTSP_VERSION_NONE
+We don't care about what version the library uses. libcurl will use whatever
+it thinks fit.
+.IP CURL_RTSP_VERSION_1_0
+Enforce RTSP 1.0 requests.
+.RE
+.IP CURLOPT_RTSP_CLIENT_CSEQ
+Manually set the the CSEQ number to issue for the next RTSP request. Useful if
+the application is resuming a previously broken connection. The CSEQ will
+increment from this new number henceforth. (Added in 7.20.x)
+.IP CURLOPT_RTSP_SERVER_CSEQ
+Manually set the CSEQ number to expect for the next RTSP Server->Client
+request.  At the moment, this feature (listening for Server requests) is
+unimplemented. (Added in 7.20.x)
+.IP CURLOPT_RTPDATA
+This is the stream that will be passed to \fICURLOPT_RTPFUNCTION\fP when
+interleaved RTP data is received. Since the application is required to provide
+a custom function for RTP data, there is no requirement that the stream
+pointer be a valid FILE pointer. An application may wish to pass a cookie
+containing information about many streams to assist in demultiplexing the
+different RTP channels. (Added in 7.20.x)
+.IP CURLOPT_RTPFUNCTION
+Function pointer that should match the following prototype: \fIsize_t
+function( void *ptr, size_t size, size_t nmemb, void *stream, int
+channel);\fP.  \fBThis does not match the prototype of fwrite()\fP. This
+function gets called by libcurl as soon as it has received interleaved RTP
+data. It operates like the other write callbacks however it requires a user
+implementation since the application must demux the different RTP
+channels. This function gets called for each $ block and therefore contains
+exactly one upper-layer protocol unit (e.g.  one RTP packet). See \fIRFC 2326
+Section 10.12\fP for more information on how RTP interleaving behaves.
+
+Interleaved RTP poses some challeneges for the client application. Since the
+stream data is sharing the RTSP control connection, it is critical to service
+the RTP in a timely fashion. If the RTP data is not handled quickly,
+subsequent response processing may become unreasonably delayed and the
+connection may close. The application may use \fICURL_RTSPREQ_RECEIVE\fP to
+service RTP data when no requests are desired. If the application makes a
+request, (e.g.  \fICURL_RTSPREQ_PAUSE\fP) then the response handler will
+process any pending RTP data before marking the request as finished.  (Added
+in 7.20.x)
 .SH PROTOCOL OPTIONS
 .IP CURLOPT_TRANSFERTEXT
 A parameter set to 1 tells the library to use ASCII mode for FTP transfers,
@@ -1301,9 +1440,13 @@ want. It should be in the format "X-Y", 
 transfers also support several intervals, separated with commas as in
 \fI"X-Y,N-M"\fP. Using this kind of multiple intervals will cause the HTTP
 server to send the response document in pieces (using standard MIME separation
-techniques). Pass a NULL to this option to disable the use of ranges.
+techniques). For RTSP, the formatting of a range should follow RFC 2326 Section
+12.29. Note that for RTSP, byte ranges are \fBnot\fP permitted. Instead, ranges
+should be given in npt, utc, or smpte formats.
+
+Pass a NULL to this option to disable the use of ranges.
 
-Ranges work on HTTP, FTP and FILE (since 7.18.0) transfers only.
+Ranges work on HTTP, FTP, FILE (since 7.18.0), and RTSP (since 7.x.x?) transfers only.
 .IP CURLOPT_RESUME_FROM
 Pass a long as parameter. It contains the offset in number of bytes that you
 want the transfer to start from. Set this option to 0 to make the transfer
@@ -1408,7 +1551,8 @@ given limit. This concerns both FTP and 
 .IP CURLOPT_TIMECONDITION
 Pass a long as parameter. This defines how the \fICURLOPT_TIMEVALUE\fP time
 value is treated. You can set this parameter to \fICURL_TIMECOND_IFMODSINCE\fP
-or \fICURL_TIMECOND_IFUNMODSINCE\fP. This feature applies to HTTP and FTP.
+or \fICURL_TIMECOND_IFUNMODSINCE\fP. This feature applies to HTTP, FTP, and
+RTSP.
 
 The last modification time of a file is not always known and in such instances
 this feature will have no effect even if the given time condition would not
Index: docs/libcurl/libcurl.m4
===================================================================
RCS file: /cvsroot/curl/curl/docs/libcurl/libcurl.m4,v
retrieving revision 1.6
diff -u -p -r1.6 libcurl.m4
--- docs/libcurl/libcurl.m4	19 Feb 2007 12:37:04 -0000	1.6
+++ docs/libcurl/libcurl.m4	14 Jan 2010 18:18:24 -0000
@@ -55,6 +55,7 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG],
   AH_TEMPLATE([LIBCURL_PROTOCOL_LDAP],[Defined if libcurl supports LDAP])
   AH_TEMPLATE([LIBCURL_PROTOCOL_DICT],[Defined if libcurl supports DICT])
   AH_TEMPLATE([LIBCURL_PROTOCOL_TFTP],[Defined if libcurl supports TFTP])
+  AH_TEMPLATE([LIBCURL_PROTOCOL_RTSP],[Defined if libcurl supports RTSP])
 
   AC_ARG_WITH(libcurl,
      AC_HELP_STRING([--with-libcurl=DIR],[look for the curl library in DIR]),
@@ -194,7 +195,7 @@ x=CURLOPT_VERBOSE;
 
 	      # We don't have --protocols, so just assume that all
 	      # protocols are available
-	      _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT"
+	      _libcurl_protocols="HTTP FTP FILE TELNET LDAP DICT TFTP RTSP"
 
 	      if test x$libcurl_feature_SSL = xyes ; then
 	         _libcurl_protocols="$_libcurl_protocols HTTPS"
Index: include/curl/curl.h
===================================================================
RCS file: /cvsroot/curl/curl/include/curl/curl.h,v
retrieving revision 1.402
diff -u -p -r1.402 curl.h
--- include/curl/curl.h	1 Jan 2010 14:52:51 -0000	1.402
+++ include/curl/curl.h	14 Jan 2010 18:18:24 -0000
@@ -197,6 +197,12 @@ typedef size_t (*curl_write_callback)(ch
                                       size_t nitems,
                                       void *outstream);
 
+typedef size_t (*curl_rtp_write_callback)(char *buffer,
+                                      size_t size,
+                                      size_t nitems,
+                                      void *outstream,
+                                      int channel);
+
 /* These are the return codes for the seek callbacks */
 #define CURL_SEEKFUNC_OK       0
 #define CURL_SEEKFUNC_FAIL     1 /* fail the entire transfer */
@@ -414,6 +420,10 @@ typedef enum {
   CURLE_SSL_ISSUER_ERROR,        /* 83 - Issuer check failed.  (Added in
                                     7.19.0) */
   CURLE_FTP_PRET_FAILED,         /* 84 - a PRET command failed */
+  CURLE_RTSP_RETURNED_ERROR,     /* 85 - RTSP return code failure */
+  CURLE_RTSP_CSEQ_ERROR,         /* 86 - mismatch of RTSP CSeq numbers */
+  CURLE_RTSP_SESSION_ERROR,      /* 87 - mismatch of RTSP Sessiion Identifiers */
+  
   CURL_LAST /* never use! */
 } CURLcode;
 
@@ -626,6 +636,7 @@ typedef enum {
 #define CURLPROTO_POP3S  (1<<15)
 #define CURLPROTO_SMTP   (1<<16)
 #define CURLPROTO_SMTPS  (1<<17)
+#define CURLPROTO_RTSP   (1<<18)
 #define CURLPROTO_ALL    (~0) /* enable everything */
 
 /* long may be 32 or 64 bits, but we should never depend on anything else
@@ -1295,6 +1306,39 @@ typedef enum {
   /* FTP: send PRET before PASV */
   CINIT(FTP_USE_PRET, LONG, 188),
 
+  /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
+  CINIT(RTSP_REQUEST, LONG, 189),
+
+  /* The RTSP session identifier */
+  CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190),
+
+  /* The RTSP stream URI */
+  CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191),
+
+  /* The Transport: header to use in RTSP requests */
+  CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192),
+
+  /* 
+   * The RTSP protocol verison. 
+   * Currently only CURL_RTSP_VERSION_1_0 is supported
+   */ 
+  CINIT(RTSP_VERSION, LONG, 193),
+
+  /* Manually initialize the client RTSP CSeq for this handle */
+  CINIT(RTSP_CLIENT_CSEQ, LONG, 194),
+
+  /* Manually initialize the server RTSP CSeq for this handle */
+  CINIT(RTSP_SERVER_CSEQ, LONG, 195),
+
+  /* The stream to pass to RTP_FUNCTION. */
+  CINIT(RTPDATA, OBJECTPOINT, 196),
+
+  /* Let the application define a custom write method for RTP data 
+   * This is like the other write callbacks with an extra parameter
+   * for the RTP channel.
+   */
+  CINIT(RTPFUNCTION, FUNCTIONPOINT, 197),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -1338,6 +1382,7 @@ typedef enum {
 #define CURLOPT_WRITEDATA CURLOPT_FILE
 #define CURLOPT_READDATA  CURLOPT_INFILE
 #define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
+#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
 
   /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
 enum {
@@ -1350,6 +1395,37 @@ enum {
   CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
 };
 
+  /* 
+   * These enums are for use with the CURLOPT_RTSP_VERSION option.
+   * However, currently there is only one version of the protocol.
+   * Application developers wishing to safeguard against a future protocol
+   * spec should specify CURL_RTSP_VERSION_1_0 explicitly
+   */
+enum {
+  CURL_RTSP_VERSION_NONE, /* let the library choose */
+  CURL_RTSP_VERSION_1_0,  /* use RTSP 1.0 in the request */
+  CURL_RTSP_VERSION_LAST  /* *ILLEGAL* rtsp versoin */
+};
+
+/*
+ * Public API enums for RTSP requests
+ */
+enum {
+    CURL_RTSPREQ_NONE, /* first in list */
+    CURL_RTSPREQ_OPTIONS,
+    CURL_RTSPREQ_DESCRIBE,
+    CURL_RTSPREQ_ANNOUNCE,
+    CURL_RTSPREQ_SETUP,
+    CURL_RTSPREQ_PLAY,
+    CURL_RTSPREQ_PAUSE,
+    CURL_RTSPREQ_TEARDOWN,
+    CURL_RTSPREQ_GET_PARAMETER,
+    CURL_RTSPREQ_SET_PARAMETER,
+    CURL_RTSPREQ_RECORD,
+    CURL_RTSPREQ_RECEIVE,
+    CURL_RTSPREQ_LAST /* last in list */
+};
+
   /* These enums are for use with the CURLOPT_NETRC option. */
 enum CURL_NETRC_OPTION {
   CURL_NETRC_IGNORED,     /* The .netrc will never be read.
@@ -1719,9 +1795,13 @@ typedef enum {
   CURLINFO_APPCONNECT_TIME  = CURLINFO_DOUBLE + 33,
   CURLINFO_CERTINFO         = CURLINFO_SLIST  + 34,
   CURLINFO_CONDITION_UNMET  = CURLINFO_LONG   + 35,
+  CURLINFO_RTSP_SESSION_ID  = CURLINFO_STRING + 36,
+  CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG   + 37,
+  CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG   + 38,
+  CURLINFO_RTSP_CSEQ_RECV   = CURLINFO_LONG   + 39,
   /* Fill in new entries below here! */
 
-  CURLINFO_LASTONE          = 35
+  CURLINFO_LASTONE          = 39
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
Index: lib/Makefile.inc
===================================================================
RCS file: /cvsroot/curl/curl/lib/Makefile.inc,v
retrieving revision 1.32
diff -u -p -r1.32 Makefile.inc
--- lib/Makefile.inc	12 Dec 2009 21:54:02 -0000	1.32
+++ lib/Makefile.inc	14 Jan 2010 18:18:24 -0000
@@ -11,7 +11,7 @@ CSOURCES = file.c timeval.c base64.c hos
   inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c	\
   strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c          \
   socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c		\
-  curl_memrchr.c imap.c pop3.c smtp.c pingpong.c
+  curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c
 
 HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\
   progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h	\
@@ -23,4 +23,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h 
   transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h	\
   tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h	\
   curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h	\
-  curl_memrchr.h imap.h pop3.h smtp.h pingpong.h
+  curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h
Index: lib/getinfo.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/getinfo.c,v
retrieving revision 1.68
diff -u -p -r1.68 getinfo.c
--- lib/getinfo.c	21 Apr 2009 11:46:16 -0000	1.68
+++ lib/getinfo.c	14 Jan 2010 18:18:25 -0000
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -235,6 +235,19 @@ CURLcode Curl_getinfo(struct SessionHand
     /* return if the condition prevented the document to get transfered */
     *param_longp = data->info.timecond;
     break;
+  case CURLINFO_RTSP_SESSION_ID:
+    *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
+    break;
+  case CURLINFO_RTSP_CLIENT_CSEQ:
+    *param_longp = data->state.rtsp_next_client_CSeq;
+    break;
+  case CURLINFO_RTSP_SERVER_CSEQ:
+    *param_longp = data->state.rtsp_next_server_CSeq;
+    break;
+  case CURLINFO_RTSP_CSEQ_RECV:
+    *param_longp = data->state.rtsp_CSeq_recv;
+    break;
+
   default:
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
Index: lib/http.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/http.c,v
retrieving revision 1.432
diff -u -p -r1.432 http.c
--- lib/http.c	7 Jan 2010 22:48:28 -0000	1.432
+++ lib/http.c	14 Jan 2010 18:18:26 -0000
@@ -98,6 +98,7 @@
 #include "multiif.h"
 #include "rawstr.h"
 #include "content_encoding.h"
+#include "rtsp.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -173,7 +174,7 @@ const struct Curl_handler Curl_handler_h
  *
  * Returns a pointer to the first matching header or NULL if none matched.
  */
-static char *checkheaders(struct SessionHandle *data, const char *thisheader)
+char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader)
 {
   struct curl_slist *head;
   size_t thislen = strlen(thisheader);
@@ -565,9 +566,9 @@ output_auth_headers(struct connectdata *
   if(authstatus->picked == CURLAUTH_BASIC) {
     /* Basic */
     if((proxy && conn->bits.proxy_user_passwd &&
-       !checkheaders(data, "Proxy-authorization:")) ||
+       !Curl_checkheaders(data, "Proxy-authorization:")) ||
        (!proxy && conn->bits.user_passwd &&
-       !checkheaders(data, "Authorization:"))) {
+       !Curl_checkheaders(data, "Authorization:"))) {
       auth="Basic";
       result = http_output_basic(conn, proxy);
       if(result)
@@ -960,41 +961,23 @@ static size_t readmoredata(char *buffer,
 }
 
 /* ------------------------------------------------------------------------- */
-/*
- * The add_buffer series of functions are used to build one large memory chunk
- * from repeated function invokes. Used so that the entire HTTP request can
- * be sent in one go.
- */
-
-struct send_buffer {
-  char *buffer;
-  size_t size_max;
-  size_t size_used;
-};
-typedef struct send_buffer send_buffer;
-
-static CURLcode add_custom_headers(struct connectdata *conn,
-                                   send_buffer *req_buffer);
-static CURLcode
- add_buffer(send_buffer *in, const void *inptr, size_t size);
+/* add_buffer functions */
 
 /*
- * add_buffer_init() sets up and returns a fine buffer struct
+ * Curl_add_buffer_init() sets up and returns a fine buffer struct
  */
-static
-send_buffer *add_buffer_init(void)
+Curl_send_buffer *Curl_add_buffer_init(void)
 {
-  return calloc(1, sizeof(send_buffer));
+  return calloc(1, sizeof(Curl_send_buffer));
 }
 
 /*
- * add_buffer_send() sends a header buffer and frees all associated memory.
+ * Curl_add_buffer_send() sends a header buffer and frees all associated memory.
  * Body data may be appended to the header data if desired.
  *
  * Returns CURLcode
  */
-static
-CURLcode add_buffer_send(send_buffer *in,
+CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
                          struct connectdata *conn,
                          long *bytes_written, /* add the number of sent bytes
                                                  to this counter */
@@ -1144,8 +1127,7 @@ CURLcode add_buffer_send(send_buffer *in
 /*
  * add_bufferf() add the formatted input to the buffer.
  */
-static
-CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
+CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
 {
   char *s;
   va_list ap;
@@ -1154,7 +1136,7 @@ CURLcode add_bufferf(send_buffer *in, co
   va_end(ap);
 
   if(s) {
-    CURLcode result = add_buffer(in, s, strlen(s));
+    CURLcode result = Curl_add_buffer(in, s, strlen(s));
     free(s);
     return result;
   }
@@ -1168,8 +1150,7 @@ CURLcode add_bufferf(send_buffer *in, co
 /*
  * add_buffer() appends a memory chunk to the existing buffer
  */
-static
-CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
+CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
 {
   char *new_rb;
   size_t new_size;
@@ -1223,6 +1204,8 @@ CURLcode add_buffer(send_buffer *in, con
 /* end of the add_buffer functions */
 /* ------------------------------------------------------------------------- */
 
+
+
 /*
  * Curl_compareheader()
  *
@@ -1320,7 +1303,7 @@ CURLcode Curl_proxyCONNECT(struct connec
   do {
     if(!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */
       char *host_port;
-      send_buffer *req_buffer;
+      Curl_send_buffer *req_buffer;
 
       infof(data, "Establish HTTP proxy tunnel to %s:%d\n",
             hostname, remote_port);
@@ -1334,7 +1317,7 @@ CURLcode Curl_proxyCONNECT(struct connec
       }
 
       /* initialize a dynamic send-buffer */
-      req_buffer = add_buffer_init();
+      req_buffer = Curl_add_buffer_init();
 
       if(!req_buffer)
         return CURLE_OUT_OF_MEMORY;
@@ -1355,7 +1338,7 @@ CURLcode Curl_proxyCONNECT(struct connec
         const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?
           "1.0" : "1.1";
 
-        if(!checkheaders(data, "Host:")) {
+        if(!Curl_checkheaders(data, "Host:")) {
           host = aprintf("Host: %s\r\n", host_port);
           if(!host) {
             free(req_buffer);
@@ -1363,17 +1346,17 @@ CURLcode Curl_proxyCONNECT(struct connec
             return CURLE_OUT_OF_MEMORY;
           }
         }
-        if(!checkheaders(data, "Proxy-Connection:"))
+        if(!Curl_checkheaders(data, "Proxy-Connection:"))
           proxyconn = "Proxy-Connection: Keep-Alive\r\n";
 
-        if(!checkheaders(data, "User-Agent:") &&
+        if(!Curl_checkheaders(data, "User-Agent:") &&
            data->set.str[STRING_USERAGENT])
           useragent = conn->allocptr.uagent;
 
         /* Send the connect request to the proxy */
         /* BLOCKING */
         result =
-          add_bufferf(req_buffer,
+          Curl_add_bufferf(req_buffer,
                       "CONNECT %s:%d HTTP/%s\r\n"
                       "%s"  /* Host: */
                       "%s"  /* Proxy-Authorization */
@@ -1390,15 +1373,15 @@ CURLcode Curl_proxyCONNECT(struct connec
           free(host);
 
         if(CURLE_OK == result)
-          result = add_custom_headers(conn, req_buffer);
+          result = Curl_add_custom_headers(conn, req_buffer);
 
         if(CURLE_OK == result)
           /* CRLF terminate the request */
-          result = add_bufferf(req_buffer, "\r\n");
+          result = Curl_add_bufferf(req_buffer, "\r\n");
 
         if(CURLE_OK == result) {
           /* Now send off the request */
-          result = add_buffer_send(req_buffer, conn,
+          result = Curl_add_buffer_send(req_buffer, conn,
                                    &data->info.request_size, 0, sockindex);
         }
         req_buffer = NULL;
@@ -1921,7 +1904,7 @@ CURLcode Curl_http_done(struct connectda
     return CURLE_OK;
 
   if(http->send_buffer) {
-    send_buffer *buff = http->send_buffer;
+    Curl_send_buffer *buff = http->send_buffer;
 
     free(buff->buffer);
     free(buff);
@@ -1978,7 +1961,7 @@ static bool use_http_1_1(const struct Se
 /* check and possibly add an Expect: header */
 static CURLcode expect100(struct SessionHandle *data,
                           struct connectdata *conn,
-                          send_buffer *req_buffer)
+                          Curl_send_buffer *req_buffer)
 {
   CURLcode result = CURLE_OK;
   const char *ptr;
@@ -1988,14 +1971,14 @@ static CURLcode expect100(struct Session
     /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
        100-continue to the headers which actually speeds up post operations
        (as there is one packet coming back from the web server) */
-    ptr = checkheaders(data, "Expect:");
+    ptr = Curl_checkheaders(data, "Expect:");
     if (ptr) {
       data->state.expect100header =
         Curl_compareheader(ptr, "Expect:", "100-continue");
     }
     else {
-      result = add_bufferf(req_buffer,
-                           "Expect: 100-continue\r\n");
+      result = Curl_add_bufferf(req_buffer,
+                         "Expect: 100-continue\r\n");
       if(result == CURLE_OK)
         data->state.expect100header = TRUE;
     }
@@ -2003,8 +1986,8 @@ static CURLcode expect100(struct Session
   return result;
 }
 
-static CURLcode add_custom_headers(struct connectdata *conn,
-                                   send_buffer *req_buffer)
+CURLcode Curl_add_custom_headers(struct connectdata *conn,
+                                   Curl_send_buffer *req_buffer)
 {
   char *ptr;
   struct curl_slist *headers=conn->data->set.headers;
@@ -2036,7 +2019,7 @@ static CURLcode add_custom_headers(struc
                 checkprefix("Content-Length", headers->data))
           ;
         else {
-          CURLcode result = add_bufferf(req_buffer, "%s\r\n", headers->data);
+          CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data);
           if(result)
             return result;
         }
@@ -2047,6 +2030,56 @@ static CURLcode add_custom_headers(struc
   return CURLE_OK;
 }
 
+CURLcode Curl_add_timecondition(struct SessionHandle *data, Curl_send_buffer *req_buffer) {
+    struct tm *tm;
+    char *buf = data->state.buffer;
+    CURLcode result = CURLE_OK;
+
+    /* The If-Modified-Since header family should have their times set in
+     * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
+     * represented in Greenwich Mean Time (GMT), without exception. For the
+     * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
+     * Time)." (see page 20 of RFC2616).
+     */
+
+#ifdef HAVE_GMTIME_R
+    /* thread-safe version */
+    struct tm keeptime;
+    tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
+#else
+    tm = gmtime(&data->set.timevalue);
+#endif
+
+    /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+    snprintf(buf, BUFSIZE-1,
+             "%s, %02d %s %4d %02d:%02d:%02d GMT",
+             Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+             tm->tm_mday,
+             Curl_month[tm->tm_mon],
+             tm->tm_year + 1900,
+             tm->tm_hour,
+             tm->tm_min,
+             tm->tm_sec);
+
+    switch(data->set.timecondition) {
+    case CURL_TIMECOND_IFMODSINCE:
+    default:
+      result = Curl_add_bufferf(req_buffer,
+                           "If-Modified-Since: %s\r\n", buf);
+      break;
+    case CURL_TIMECOND_IFUNMODSINCE:
+      result = Curl_add_bufferf(req_buffer,
+                           "If-Unmodified-Since: %s\r\n", buf);
+      break;
+    case CURL_TIMECOND_LASTMOD:
+      result = Curl_add_bufferf(req_buffer,
+                           "Last-Modified: %s\r\n", buf);
+      break;
+    }
+
+    return result;
+}
+
 /*
  * Curl_http() gets called from the generic Curl_do() function when a HTTP
  * request is to be performed. This creates and sends a properly constructed
@@ -2055,7 +2088,6 @@ static CURLcode add_custom_headers(struc
 CURLcode Curl_http(struct connectdata *conn, bool *done)
 {
   struct SessionHandle *data=conn->data;
-  char *buf = data->state.buffer; /* this is a short cut to the buffer */
   CURLcode result=CURLE_OK;
   struct HTTP *http;
   const char *ppath = data->state.path;
@@ -2069,7 +2101,7 @@ CURLcode Curl_http(struct connectdata *c
   char *addcookies = NULL;
   curl_off_t included_body = 0;
   const char *httpstring;
-  send_buffer *req_buffer;
+  Curl_send_buffer *req_buffer;
   curl_off_t postsize; /* off_t type to be able to hold a large file size */
   int seekerr = CURL_SEEKFUNC_OK;
 
@@ -2140,7 +2172,7 @@ CURLcode Curl_http(struct connectdata *c
      it might have been used in the proxy connect, but if we have got a header
      with the user-agent string specified, we erase the previously made string
      here. */
-  if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
+  if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
     free(conn->allocptr.uagent);
     conn->allocptr.uagent=NULL;
   }
@@ -2161,15 +2193,15 @@ CURLcode Curl_http(struct connectdata *c
     conn->bits.authneg = FALSE;
 
   Curl_safefree(conn->allocptr.ref);
-  if(data->change.referer && !checkheaders(data, "Referer:"))
+  if(data->change.referer && !Curl_checkheaders(data, "Referer:"))
     conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
   else
     conn->allocptr.ref = NULL;
 
-  if(data->set.str[STRING_COOKIE] && !checkheaders(data, "Cookie:"))
+  if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, "Cookie:"))
     addcookies = data->set.str[STRING_COOKIE];
 
-  if(!checkheaders(data, "Accept-Encoding:") &&
+  if(!Curl_checkheaders(data, "Accept-Encoding:") &&
      data->set.str[STRING_ENCODING]) {
     Curl_safefree(conn->allocptr.accept_encoding);
     conn->allocptr.accept_encoding =
@@ -2178,7 +2210,7 @@ CURLcode Curl_http(struct connectdata *c
       return CURLE_OUT_OF_MEMORY;
   }
 
-  ptr = checkheaders(data, "Transfer-Encoding:");
+  ptr = Curl_checkheaders(data, "Transfer-Encoding:");
   if(ptr) {
     /* Some kind of TE is requested, check if 'chunked' is chosen */
     data->req.upload_chunky =
@@ -2207,7 +2239,7 @@ CURLcode Curl_http(struct connectdata *c
 
   Curl_safefree(conn->allocptr.host);
 
-  ptr = checkheaders(data, "Host:");
+  ptr = Curl_checkheaders(data, "Host:");
   if(ptr && (!data->state.this_is_a_follow ||
              Curl_raw_equal(data->state.first_host, conn->host.name))) {
 #if !defined(CURL_DISABLE_COOKIES)
@@ -2334,7 +2366,7 @@ CURLcode Curl_http(struct connectdata *c
     /* we must build the whole darned post sequence first, so that we have
        a size of the whole shebang before we start to send it */
      result = Curl_getFormData(&http->sendit, data->set.httppost,
-                               checkheaders(data, "Content-Type:"),
+                               Curl_checkheaders(data, "Content-Type:"),
                                &http->postsize);
      if(CURLE_OK != result) {
        /* Curl_getFormData() doesn't use failf() */
@@ -2344,7 +2376,7 @@ CURLcode Curl_http(struct connectdata *c
   }
 
 
-  http->p_accept = checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n";
+  http->p_accept = Curl_checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n";
 
   if(( (HTTPREQ_POST == httpreq) ||
        (HTTPREQ_POST_FORM == httpreq) ||
@@ -2427,7 +2459,7 @@ CURLcode Curl_http(struct connectdata *c
      * ones if any such are specified.
      */
     if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
-       !checkheaders(data, "Range:")) {
+       !Curl_checkheaders(data, "Range:")) {
       /* if a line like this was already allocated, free the previous one */
       if(conn->allocptr.rangeline)
         free(conn->allocptr.rangeline);
@@ -2435,7 +2467,7 @@ CURLcode Curl_http(struct connectdata *c
                                          data->state.range);
     }
     else if((httpreq != HTTPREQ_GET) &&
-            !checkheaders(data, "Content-Range:")) {
+            !Curl_checkheaders(data, "Content-Range:")) {
 
       /* if a line like this was already allocated, free the previous one */
       if(conn->allocptr.rangeline)
@@ -2478,27 +2510,27 @@ CURLcode Curl_http(struct connectdata *c
   httpstring= use_http_1_1(data, conn)?"1.1":"1.0";
 
   /* initialize a dynamic send-buffer */
-  req_buffer = add_buffer_init();
+  req_buffer = Curl_add_buffer_init();
 
   if(!req_buffer)
     return CURLE_OUT_OF_MEMORY;
 
   /* add the main request stuff */
   /* GET/HEAD/POST/PUT */
-  result = add_bufferf(req_buffer, "%s ", request);
+  result = Curl_add_bufferf(req_buffer, "%s ", request);
   if (result)
     return result;
 
   /* url */
   if (paste_ftp_userpwd)
-    result = add_bufferf(req_buffer, "ftp://%s:%s@%s",
+    result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
         conn->user, conn->passwd, ppath + sizeof("ftp://") - 1);
   else
-    result = add_buffer(req_buffer, ppath, strlen(ppath));
+    result = Curl_add_buffer(req_buffer, ppath, strlen(ppath));
   if (result)
     return result;
 
-  result = add_bufferf(req_buffer,
+  result = Curl_add_bufferf(req_buffer,
                 "%s" /* ftp typecode (;type=x) */
                 " HTTP/%s\r\n" /* HTTP version */
                 "%s" /* proxyuserpwd */
@@ -2532,7 +2564,7 @@ CURLcode Curl_http(struct connectdata *c
                 conn->allocptr.ref:"" /* Referer: <data> */,
                 (conn->bits.httpproxy &&
                  !conn->bits.tunnel_proxy &&
-                 !checkheaders(data, "Proxy-Connection:"))?
+                 !Curl_checkheaders(data, "Proxy-Connection:"))?
                 "Proxy-Connection: Keep-Alive\r\n":"",
                 te
       );
@@ -2568,11 +2600,11 @@ CURLcode Curl_http(struct connectdata *c
       while(co) {
         if(co->value) {
           if(0 == count) {
-            result = add_bufferf(req_buffer, "Cookie: ");
+            result = Curl_add_bufferf(req_buffer, "Cookie: ");
             if(result)
               break;
           }
-          result = add_bufferf(req_buffer,
+          result = Curl_add_bufferf(req_buffer,
                                "%s%s=%s", count?"; ":"",
                                co->name, co->value);
           if(result)
@@ -2585,16 +2617,16 @@ CURLcode Curl_http(struct connectdata *c
     }
     if(addcookies && (CURLE_OK == result)) {
       if(!count)
-        result = add_bufferf(req_buffer, "Cookie: ");
+        result = Curl_add_bufferf(req_buffer, "Cookie: ");
       if(CURLE_OK == result) {
-        result = add_bufferf(req_buffer, "%s%s",
+        result = Curl_add_bufferf(req_buffer, "%s%s",
                              count?"; ":"",
                              addcookies);
         count++;
       }
     }
     if(count && (CURLE_OK == result))
-      result = add_buffer(req_buffer, "\r\n", 2);
+      result = Curl_add_buffer(req_buffer, "\r\n", 2);
 
     if(result)
       return result;
@@ -2602,54 +2634,12 @@ CURLcode Curl_http(struct connectdata *c
 #endif
 
   if(data->set.timecondition) {
-    struct tm *tm;
-
-    /* The If-Modified-Since header family should have their times set in
-     * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
-     * represented in Greenwich Mean Time (GMT), without exception. For the
-     * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
-     * Time)." (see page 20 of RFC2616).
-     */
-
-#ifdef HAVE_GMTIME_R
-    /* thread-safe version */
-    struct tm keeptime;
-    tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
-#else
-    tm = gmtime(&data->set.timevalue);
-#endif
-
-    /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
-    snprintf(buf, BUFSIZE-1,
-             "%s, %02d %s %4d %02d:%02d:%02d GMT",
-             Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
-             tm->tm_mday,
-             Curl_month[tm->tm_mon],
-             tm->tm_year + 1900,
-             tm->tm_hour,
-             tm->tm_min,
-             tm->tm_sec);
-
-    switch(data->set.timecondition) {
-    case CURL_TIMECOND_IFMODSINCE:
-    default:
-      result = add_bufferf(req_buffer,
-                           "If-Modified-Since: %s\r\n", buf);
-      break;
-    case CURL_TIMECOND_IFUNMODSINCE:
-      result = add_bufferf(req_buffer,
-                           "If-Unmodified-Since: %s\r\n", buf);
-      break;
-    case CURL_TIMECOND_LASTMOD:
-      result = add_bufferf(req_buffer,
-                           "Last-Modified: %s\r\n", buf);
-      break;
-    }
+      result = Curl_add_timecondition(data, req_buffer);
     if(result)
       return result;
   }
 
-  result = add_custom_headers(conn, req_buffer);
+  result = Curl_add_custom_headers(conn, req_buffer);
   if(result)
     return result;
 
@@ -2665,11 +2655,11 @@ CURLcode Curl_http(struct connectdata *c
   case HTTPREQ_POST_FORM:
     if(!http->sendit || conn->bits.authneg) {
       /* nothing to post! */
-      result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
+      result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
       if(result)
         return result;
 
-      result = add_buffer_send(req_buffer, conn,
+      result = Curl_add_buffer_send(req_buffer, conn,
                                &data->info.request_size, 0, FIRSTSOCKET);
       if(result)
         failf(data, "Failed sending POST request");
@@ -2701,7 +2691,7 @@ CURLcode Curl_http(struct connectdata *c
 
     if(!data->req.upload_chunky) {
       /* only add Content-Length if not uploading chunked */
-      result = add_bufferf(req_buffer,
+      result = Curl_add_bufferf(req_buffer,
                            "Content-Length: %" FORMAT_OFF_T "\r\n",
                            http->postsize);
       if(result)
@@ -2725,13 +2715,13 @@ CURLcode Curl_http(struct connectdata *c
         return CURLE_HTTP_POST_ERROR;
       }
 
-      result = add_buffer(req_buffer, contentType, linelength);
+      result = Curl_add_buffer(req_buffer, contentType, linelength);
       if(result)
         return result;
     }
 
     /* make the request end in a true CRLF */
-    result = add_buffer(req_buffer, "\r\n", 2);
+    result = Curl_add_buffer(req_buffer, "\r\n", 2);
     if(result)
       return result;
 
@@ -2739,7 +2729,7 @@ CURLcode Curl_http(struct connectdata *c
     Curl_pgrsSetUploadSize(data, http->postsize);
 
     /* fire away the whole request to the server */
-    result = add_buffer_send(req_buffer, conn,
+    result = Curl_add_buffer_send(req_buffer, conn,
                              &data->info.request_size, 0, FIRSTSOCKET);
     if(result)
       failf(data, "Failed sending POST request");
@@ -2773,7 +2763,7 @@ CURLcode Curl_http(struct connectdata *c
 
     if((postsize != -1) && !data->req.upload_chunky) {
       /* only add Content-Length if not uploading chunked */
-      result = add_bufferf(req_buffer,
+      result = Curl_add_bufferf(req_buffer,
                            "Content-Length: %" FORMAT_OFF_T "\r\n",
                            postsize );
       if(result)
@@ -2784,7 +2774,7 @@ CURLcode Curl_http(struct connectdata *c
     if(result)
       return result;
 
-    result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
+    result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
     if(result)
       return result;
 
@@ -2792,7 +2782,7 @@ CURLcode Curl_http(struct connectdata *c
     Curl_pgrsSetUploadSize(data, postsize);
 
     /* this sends the buffer and frees all the buffer resources */
-    result = add_buffer_send(req_buffer, conn,
+    result = Curl_add_buffer_send(req_buffer, conn,
                              &data->info.request_size, 0, FIRSTSOCKET);
     if(result)
       failf(data, "Failed sending PUT request");
@@ -2822,10 +2812,10 @@ CURLcode Curl_http(struct connectdata *c
          we don't upload data chunked, as RFC2616 forbids us to set both
          kinds of headers (Transfer-Encoding: chunked and Content-Length) */
 
-      if(conn->bits.authneg || !checkheaders(data, "Content-Length:")) {
+      if(conn->bits.authneg || !Curl_checkheaders(data, "Content-Length:")) {
         /* we allow replacing this header if not during auth negotiation,
            although it isn't very wise to actually set your own */
-        result = add_bufferf(req_buffer,
+        result = Curl_add_bufferf(req_buffer,
                              "Content-Length: %" FORMAT_OFF_T"\r\n",
                              postsize);
         if(result)
@@ -2833,8 +2823,8 @@ CURLcode Curl_http(struct connectdata *c
       }
     }
 
-    if(!checkheaders(data, "Content-Type:")) {
-      result = add_bufferf(req_buffer,
+    if(!Curl_checkheaders(data, "Content-Type:")) {
+      result = Curl_add_bufferf(req_buffer,
                            "Content-Type: application/x-www-form-urlencoded\r\n");
       if(result)
         return result;
@@ -2844,7 +2834,7 @@ CURLcode Curl_http(struct connectdata *c
        the somewhat bigger ones we allow the app to disable it. Just make
        sure that the expect100header is always set to the preferred value
        here. */
-    ptr = checkheaders(data, "Expect:");
+    ptr = Curl_checkheaders(data, "Expect:");
     if(ptr) {
       data->state.expect100header =
         Curl_compareheader(ptr, "Expect:", "100-continue");
@@ -2868,25 +2858,25 @@ CURLcode Curl_http(struct connectdata *c
            is no magic limit but only set to prevent really huge POSTs to
            get the data duplicated with malloc() and family. */
 
-        result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+        result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
         if(result)
           return result;
 
         if(!data->req.upload_chunky) {
           /* We're not sending it 'chunked', append it to the request
              already now to reduce the number if send() calls */
-          result = add_buffer(req_buffer, data->set.postfields,
+          result = Curl_add_buffer(req_buffer, data->set.postfields,
                               (size_t)postsize);
           included_body = postsize;
         }
         else {
           /* Append the POST data chunky-style */
-          result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
+          result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize);
           if(CURLE_OK == result)
-            result = add_buffer(req_buffer, data->set.postfields,
+            result = Curl_add_buffer(req_buffer, data->set.postfields,
                                 (size_t)postsize);
           if(CURLE_OK == result)
-            result = add_buffer(req_buffer,
+            result = Curl_add_buffer(req_buffer,
                                 "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
           /* CR  LF   0  CR  LF  CR  LF */
           included_body = postsize + 7;
@@ -2907,20 +2897,20 @@ CURLcode Curl_http(struct connectdata *c
         /* set the upload size to the progress meter */
         Curl_pgrsSetUploadSize(data, http->postsize);
 
-        result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+        result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
         if(result)
           return result;
       }
     }
     else {
-      result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+      result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
       if(result)
         return result;
 
       if(data->req.upload_chunky && conn->bits.authneg) {
         /* Chunky upload is selected and we're negotiating auth still, send
            end-of-data only */
-        result = add_buffer(req_buffer,
+        result = Curl_add_buffer(req_buffer,
                             "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
         /* CR  LF   0  CR  LF  CR  LF */
         if(result)
@@ -2941,7 +2931,7 @@ CURLcode Curl_http(struct connectdata *c
       }
     }
     /* issue the request */
-    result = add_buffer_send(req_buffer, conn, &data->info.request_size,
+    result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size,
                              (size_t)included_body, FIRSTSOCKET);
 
     if(result)
@@ -2955,12 +2945,12 @@ CURLcode Curl_http(struct connectdata *c
     break;
 
   default:
-    result = add_buffer(req_buffer, "\r\n", 2);
+    result = Curl_add_buffer(req_buffer, "\r\n", 2);
     if(result)
       return result;
 
     /* issue the request */
-    result = add_buffer_send(req_buffer, conn,
+    result = Curl_add_buffer_send(req_buffer, conn,
                              &data->info.request_size, 0, FIRSTSOCKET);
 
     if(result)
@@ -2999,12 +2989,11 @@ checkhttpprefix(struct SessionHandle *da
   bool rc = FALSE;
 #ifdef CURL_DOES_CONVERSIONS
   /* convert from the network encoding using a scratch area */
-  char *scratch = calloc(1, strlen(s)+1);
+  char *scratch = strdup(s);
   if(NULL == scratch) {
-     failf (data, "Failed to calloc memory for conversion!");
+     failf (data, "Failed to allocate memory for conversion!");
      return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
   }
-  strcpy(scratch, s);
   if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
     /* Curl_convert_from_network calls failf if unsuccessful */
      free(scratch);
@@ -3031,6 +3020,50 @@ checkhttpprefix(struct SessionHandle *da
   return rc;
 }
 
+#ifndef CURL_DISABLE_RTSP
+static bool
+checkrtspprefix(struct SessionHandle *data,
+        const char *s)
+{
+
+#ifdef CURL_DOES_CONVERSIONS
+  /* convert from the network encoding using a scratch area */
+  char *scratch = strdup(s);
+  if(NULL == scratch) {
+    failf (data, "Failed to allocate memory for conversion!");
+    return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
+  }
+  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+    /* Curl_convert_from_network calls failf if unsuccessful */
+    free(scratch);
+    return FALSE; /* can't return CURLE_foobar so return FALSE */
+  }
+  s = scratch;
+#else
+  (void)data; /* unused */
+#endif /* CURL_DOES_CONVERSIONS */
+  if(checkprefix("RTSP/", s))
+    return TRUE;
+  else
+    return FALSE;
+}
+#endif /* CURL_DISABLE_RTSP */
+
+static bool
+checkprotoprefix(struct SessionHandle *data, struct connectdata *conn, const char *s)
+{
+#ifndef CURL_DISABLE_RTSP
+  if(conn->protocol & PROT_RTSP)
+    return checkrtspprefix(data, s);
+#endif /* CURL_DISABLE_RTSP */
+
+  return checkhttpprefix(data, s);
+}
+
+#endif
+
+
+
 /*
  * header_append() copies a chunk of data to the end of the already received
  * header. We make sure that the full string fit in the allocated header
@@ -3079,12 +3112,13 @@ static CURLcode header_append(struct Ses
  * Read any HTTP header lines from the server and pass them to the client app.
  */
 CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
-                                     struct connectdata *conn,
-                                     ssize_t *nread,
-                                     bool *stop_reading)
+                                       struct connectdata *conn,
+                                       ssize_t *nread,
+                                       bool *stop_reading)
 {
   CURLcode result;
   struct SingleRequest *k = &data->req;
+  long CSeq = 0;
 
   /* header line within buffer loop */
   do {
@@ -3106,9 +3140,9 @@ CURLcode Curl_http_readwrite_headers(str
         return result;
 
       if(!k->headerline && (k->hbuflen>5)) {
-        /* make a first check that this looks like a HTTP header */
-        if(!checkhttpprefix(data, data->state.headerbuff)) {
-          /* this is not the beginning of a HTTP first header line */
+        /* make a first check that this looks like a protocol header */
+        if(!checkprotoprefix(data, conn, data->state.headerbuff)) {
+          /* this is not the beginning of a protocol first header line */
           k->header = FALSE;
           k->badheader = HEADER_ALLBAD;
           break;
@@ -3140,8 +3174,8 @@ CURLcode Curl_http_readwrite_headers(str
     if(!k->headerline) {
       /* the first read header */
       if((k->hbuflen>5) &&
-         !checkhttpprefix(data, data->state.headerbuff)) {
-        /* this is not the beginning of a HTTP first header line */
+         !checkprotoprefix(data, conn, data->state.headerbuff)) {
+        /* this is not the beginning of a protocol first header line */
         k->header = FALSE;
         if(*nread)
           /* since there's more, this is a partial bad header */
@@ -3198,7 +3232,7 @@ CURLcode Curl_http_readwrite_headers(str
         k->header = FALSE; /* no more header to parse! */
 
         if((k->size == -1) && !k->chunk && !conn->bits.close &&
-           (conn->httpversion >= 11) ) {
+           (conn->httpversion >= 11) && !(conn->protocol & PROT_RTSP)) {
           /* On HTTP 1.1, when connection is not to get closed, but no
              Content-Length nor Content-Encoding chunked have been
              received, according to RFC2616 section 4.4 point 5, we
@@ -3310,6 +3344,7 @@ CURLcode Curl_http_readwrite_headers(str
           Curl_pgrsSetDownloadSize(data, k->size);
           k->maxdownload = k->size;
         }
+
         /* If max download size is *zero* (nothing) we already
            have nothing and can safely return ok now! */
         if(0 == k->maxdownload)
@@ -3341,6 +3376,7 @@ CURLcode Curl_http_readwrite_headers(str
       /* This is the first header, it MUST be the error code line
          or else we consider this to be the body right away! */
       int httpversion_major;
+      int rtspversion_major;
       int nc;
 #ifdef CURL_DOES_CONVERSIONS
 #define HEADER1 scratch
@@ -3365,35 +3401,53 @@ CURLcode Curl_http_readwrite_headers(str
 #define HEADER1 k->p /* no conversion needed, just use k->p */
 #endif /* CURL_DOES_CONVERSIONS */
 
-      nc = sscanf(HEADER1,
-                  " HTTP/%d.%d %3d",
-                  &httpversion_major,
-                  &conn->httpversion,
-                  &k->httpcode);
-      if(nc==3) {
-        conn->httpversion += 10 * httpversion_major;
-      }
-      else {
-        /* this is the real world, not a Nirvana
-           NCSA 1.5.x returns this crap when asked for HTTP/1.1
-        */
-        nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
-        conn->httpversion = 10;
+      if(conn->protocol & PROT_HTTP) {
+        nc = sscanf(HEADER1,
+            " HTTP/%d.%d %3d",
+            &httpversion_major,
+            &conn->httpversion,
+            &k->httpcode);
+        if(nc==3) {
+          conn->httpversion += 10 * httpversion_major;
+        }
+        else {
+          /* this is the real world, not a Nirvana
+             NCSA 1.5.x returns this crap when asked for HTTP/1.1
+             */
+          nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
+          conn->httpversion = 10;
 
-        /* If user has set option HTTP200ALIASES,
-           compare header line against list of aliases
-        */
-        if(!nc) {
-          if(checkhttpprefix(data, k->p)) {
-            nc = 1;
-            k->httpcode = 200;
-            conn->httpversion = 10;
+          /* If user has set option HTTP200ALIASES,
+             compare header line against list of aliases
+             */
+          if(!nc) {
+            if(checkhttpprefix(data, k->p)) {
+              nc = 1;
+              k->httpcode = 200;
+              conn->httpversion = 10;
+            }
           }
         }
       }
+      else if(conn->protocol & PROT_RTSP) {
+        nc = sscanf(HEADER1,
+                    " RTSP/%d.%d %3d",
+                    &rtspversion_major,
+                    &conn->rtspversion,
+                    &k->httpcode);
+        if(nc==3) {
+          conn->rtspversion += 10 * rtspversion_major;
+          conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
+        }
+        else {
+          /* TODO: do we care about the other cases here? */
+          nc = 0;
+        }
+      }
 
       if(nc) {
         data->info.httpcode = k->httpcode;
+
         data->info.httpversion = conn->httpversion;
         if (!data->state.httpversion ||
             data->state.httpversion > conn->httpversion)
@@ -3571,8 +3625,8 @@ CURLcode Curl_http_readwrite_headers(str
        */
       conn->bits.close = TRUE; /* close when done */
     }
-    else if(Curl_compareheader(k->p,
-                               "Transfer-Encoding:", "chunked")) {
+    else if(Curl_compareheader(k->p, "Transfer-Encoding:", "chunked") &&
+            !(conn->protocol & PROT_RTSP)) {
       /*
        * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
        * means that the server will send a series of "chunks". Each
@@ -3708,6 +3762,64 @@ CURLcode Curl_http_readwrite_headers(str
         }
       }
     }
+    else if((conn->protocol & PROT_RTSP) && checkprefix("CSeq:", k->p)) {
+      /* Store the received CSeq. Match is verified in rtsp_done */
+      int nc;
+      char *temp = strdup(k->p);
+      if(!temp)
+        return CURLE_OUT_OF_MEMORY;
+      Curl_strntoupper(temp, temp, sizeof(temp));
+      nc = sscanf(temp, "CSEQ: %ld", &CSeq);
+      free(temp);
+      if(nc == 1) {
+        data->state.proto.rtsp->CSeq_recv = CSeq; /* mark the request */
+        data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
+      }
+      else {
+        failf(data, "Unable to read the CSeq header: [%s]", k->p);
+        return CURLE_RTSP_CSEQ_ERROR;
+      }
+    }
+    else if((conn->protocol & PROT_RTSP) && checkprefix("Session:", k->p)) {
+      char *start;
+
+      /* Find the first non-space letter */
+      start = k->p + 9;
+      while(*start && ISSPACE(*start))
+        start++;
+
+      if(!start) {
+        failf(data, "Got a blank Session ID");
+      } else if(data->set.str[STRING_RTSP_SESSION_ID]) {
+        /* If the Session ID is set, then compare */
+        if(strncmp(start, data->set.str[STRING_RTSP_SESSION_ID],
+                   strlen(data->set.str[STRING_RTSP_SESSION_ID]))  != 0) {
+          failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
+                start, data->set.str[STRING_RTSP_SESSION_ID]);
+          return CURLE_RTSP_SESSION_ERROR;
+        }
+      } else {
+        /* If the Session ID is not set, and we find it in a response, then
+           set it */
+
+        /* The session ID can be an alphanumeric or a 'safe' character
+         *
+         * RFC 2326 15.1 Base Syntax:
+         * safe =  "\$" | "-" | "_" | "." | "+"
+         * */
+        char *end = start;
+        while(*end &&
+            (ISALNUM(*end) || *end == '-' || *end == '_' || *end == '.' ||
+             *end == '+' ||
+             (*end == '\\' && *(end + 1) && *(end + 1) == '$' && (++end, 1))))
+          end++;
+
+        /* Copy the id substring into a new buffer */
+        data->set.str[STRING_RTSP_SESSION_ID] = malloc(end - start + 1);
+        memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, end - start);
+        (data->set.str[STRING_RTSP_SESSION_ID])[end - start] = '\0';
+      }
+    }
 
     /*
      * End of header-checks. Write them to the client.
@@ -3741,4 +3853,3 @@ CURLcode Curl_http_readwrite_headers(str
   return CURLE_OK;
 }
 
-#endif
Index: lib/http.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/http.h,v
retrieving revision 1.42
diff -u -p -r1.42 http.h
--- lib/http.h	7 Jan 2010 22:48:28 -0000	1.42
+++ lib/http.h	14 Jan 2010 18:18:26 -0000
@@ -35,8 +35,40 @@ bool Curl_compareheader(const char *head
                         const char *header,   /* header keyword _with_ colon */
                         const char *content); /* content string to find */
 
+char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader);
+
 char *Curl_copy_header_value(const char *h);
 
+
+/* ------------------------------------------------------------------------- */
+/*
+ * The add_buffer series of functions are used to build one large memory chunk
+ * from repeated function invokes. Used so that the entire HTTP request can
+ * be sent in one go.
+ */
+struct Curl_send_buffer {
+  char *buffer;
+  size_t size_max;
+  size_t size_used;
+};
+typedef struct Curl_send_buffer Curl_send_buffer;
+
+Curl_send_buffer *Curl_add_buffer_init(void);
+CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...);
+CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size);
+CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+                         struct connectdata *conn,
+                         long *bytes_written,
+                         size_t included_body_bytes,
+                         int socketindex);
+
+
+CURLcode Curl_add_timecondition(struct SessionHandle *data,
+                                Curl_send_buffer *buf);
+CURLcode Curl_add_custom_headers(struct connectdata *conn,
+                                   Curl_send_buffer *req_buffer);
+
+
 /* ftp can use this as well */
 CURLcode Curl_proxyCONNECT(struct connectdata *conn,
                            int tunnelsocket,
Index: lib/sendf.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/sendf.c,v
retrieving revision 1.159
diff -u -p -r1.159 sendf.c
--- lib/sendf.c	10 Jun 2009 21:26:11 -0000	1.159
+++ lib/sendf.c	14 Jan 2010 18:18:26 -0000
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -43,6 +43,7 @@
 #include "sslgen.h"
 #include "ssh.h"
 #include "multiif.h"
+#include "rtsp.h"
 
 #define _MPRINTF_REPLACE /* use the internal *printf() functions */
 #include <curl/mprintf.h>
@@ -455,6 +456,26 @@ CURLcode Curl_client_write(struct connec
     }
   }
 
+  if(type & CLIENTWRITE_RTP) {
+    if((conn->protocol & PROT_RTSP) && data->set.fwrite_rtp) {
+      /* Write the RTP data to user supplied channel pointer */
+      wrote = data->set.fwrite_rtp(ptr, 1, len, data->set.rtp_out,
+                                   conn->proto.rtspc.rtp_channel);
+
+      if(CURL_WRITEFUNC_PAUSE == wrote)
+        return pausewrite(data, type, ptr, len);
+
+      if(wrote != len) {
+        failf (data, "Failed writing RTP data");
+        return CURLE_WRITE_ERROR;
+      }
+    }
+    else {
+      failf (data, "Got RTP data without an RTP write callback.");
+      return CURLE_WRITE_ERROR;
+    }
+  }
+
   return CURLE_OK;
 }
 
Index: lib/sendf.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/sendf.h,v
retrieving revision 1.47
diff -u -p -r1.47 sendf.h
--- lib/sendf.h	11 Dec 2009 02:14:11 -0000	1.47
+++ lib/sendf.h	14 Jan 2010 18:18:26 -0000
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -48,9 +48,10 @@ void Curl_failf(struct SessionHandle *, 
 
 #define failf Curl_failf
 
-#define CLIENTWRITE_BODY   1
-#define CLIENTWRITE_HEADER 2
+#define CLIENTWRITE_BODY   (1<<0)
+#define CLIENTWRITE_HEADER (1<<1)
 #define CLIENTWRITE_BOTH   (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
+#define CLIENTWRITE_RTP    (1<<2)
 
 CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
                            size_t len);
Index: lib/setup.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/setup.h,v
retrieving revision 1.173
diff -u -p -r1.173 setup.h
--- lib/setup.h	30 Dec 2009 17:59:56 -0000	1.173
+++ lib/setup.h	14 Jan 2010 18:18:26 -0000
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -169,6 +169,7 @@
 #  define CURL_DISABLE_TELNET
 #  define CURL_DISABLE_DICT
 #  define CURL_DISABLE_FILE
+#  define CURL_DISABLE_RTSP
 #endif
 
 /* ================================================================ */
Index: lib/strerror.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/strerror.c,v
retrieving revision 1.58
diff -u -p -r1.58 strerror.c
--- lib/strerror.c	1 Jan 2010 14:52:52 -0000	1.58
+++ lib/strerror.c	14 Jan 2010 18:18:26 -0000
@@ -270,6 +270,15 @@ curl_easy_strerror(CURLcode error)
   case CURLE_AGAIN:
     return "Socket not ready for send/recv";
 
+  case CURLE_RTSP_RETURNED_ERROR:
+    return "RTSP response code said error";
+
+  case CURLE_RTSP_CSEQ_ERROR:
+    return "RTSP CSeq mismatch or invalid CSeq";
+
+  case CURLE_RTSP_SESSION_ERROR:
+    return "RTSP session error";
+
     /* error codes not used by current libcurl */
   case CURLE_OBSOLETE4:
   case CURLE_OBSOLETE10:
Index: lib/transfer.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/transfer.c,v
retrieving revision 1.448
diff -u -p -r1.448 transfer.c
--- lib/transfer.c	7 Jan 2010 22:48:28 -0000	1.448
+++ lib/transfer.c	14 Jan 2010 18:18:27 -0000
@@ -103,6 +103,7 @@
 #include "select.h"
 #include "multiif.h"
 #include "easyif.h" /* for Curl_convert_to_network prototype */
+#include "rtsp.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -124,7 +125,7 @@ CURLcode Curl_fillreadbuffer(struct conn
 #ifdef CURL_DOES_CONVERSIONS
   bool sending_http_headers = FALSE;
 
-  if((conn->protocol&PROT_HTTP) &&
+  if((conn->protocol&(PROT_HTTP|PROT_RTSP)) &&
      (data->state.proto.http->sending == HTTPSEND_REQUEST)) {
     /* We're sending the HTTP request headers, not the data.
        Remember that so we don't re-translate them into garbage. */
@@ -368,6 +369,7 @@ static CURLcode readwrite_data(struct Se
   CURLcode result = CURLE_OK;
   ssize_t nread; /* number of bytes read */
   bool is_empty_data = FALSE;
+  bool readmore = FALSE; /* used by RTP to signal for more data */
 
   *done = FALSE;
 
@@ -435,6 +437,19 @@ static CURLcode readwrite_data(struct Se
        in the flow below before the actual storing is done. */
     k->str = k->buf;
 
+#ifndef CURL_DISABLE_RTSP
+    if(conn->protocol & PROT_RTSP) {
+      readmore = FALSE;
+      result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore, done);
+      if(result)
+        return result;
+      if(readmore)
+        break;
+      if(*done)
+        return CURLE_OK;
+    }
+#endif
+
 #ifndef CURL_DISABLE_HTTP
     /* Since this is a two-state thing, we check if we are parsing
        headers at the moment or not. */
@@ -456,11 +471,12 @@ static CURLcode readwrite_data(struct Se
        is non-headers. */
     if(k->str && !k->header && (nread > 0 || is_empty_data)) {
 
+
 #ifndef CURL_DISABLE_HTTP
       if(0 == k->bodywrites && !is_empty_data) {
         /* These checks are only made the first time we are about to
            write a piece of the body */
-        if(conn->protocol&PROT_HTTP) {
+        if(conn->protocol&(PROT_HTTP|PROT_RTSP)) {
           /* HTTP-only checks */
 
           if(data->req.newurl) {
@@ -747,7 +763,7 @@ static CURLcode readwrite_upload(struct 
           break;
         }
 
-        if(conn->protocol&PROT_HTTP) {
+        if(conn->protocol&(PROT_HTTP|PROT_RTSP)) {
           if(data->state.proto.http->sending == HTTPSEND_REQUEST)
             /* We're sending the HTTP request headers, not the data.
                Remember that so we don't change the line endings. */
@@ -846,7 +862,7 @@ static CURLcode readwrite_upload(struct 
 
     /* write to socket (send away data) */
     result = Curl_write(conn,
-                        conn->writesockfd,         /* socket to send to */
+                        conn->writesockfd,     /* socket to send to */
                         data->req.upload_fromhere, /* buffer pointer */
                         data->req.upload_present,  /* buffer size */
                         &bytes_written);           /* actually sent */
@@ -1825,14 +1841,15 @@ CURLcode Curl_retry_request(struct conne
 
   /* if we're talking upload, we can't do the checks below, unless the protocol
      is HTTP as when uploading over HTTP we will still get a response */
-  if(data->set.upload && !(conn->protocol&PROT_HTTP))
+  if(data->set.upload && !(conn->protocol&(PROT_HTTP|PROT_RTSP)))
     return CURLE_OK;
 
   if(/* workaround for broken TLS servers */ data->state.ssl_connect_retry ||
       ((data->req.bytecount +
-      data->req.headerbytecount == 0) &&
-     conn->bits.reuse &&
-     !data->set.opt_no_body)) {
+        data->req.headerbytecount == 0) &&
+        conn->bits.reuse &&
+        !data->set.opt_no_body &&
+        data->set.rtspreq != RTSPREQ_RECEIVE)) {
     /* We got no data, we attempted to re-use a connection and yet we want a
        "body". This might happen if the connection was left alive when we were
        done using it before, but that was closed when we wanted to read from
Index: lib/url.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/url.c,v
retrieving revision 1.827
diff -u -p -r1.827 url.c
--- lib/url.c	6 Jan 2010 16:01:48 -0000	1.827
+++ lib/url.c	14 Jan 2010 18:18:29 -0000
@@ -136,6 +136,7 @@ void idn_free (void *ptr); /* prototype 
 #include "inet_ntop.h"
 #include "http_ntlm.h"
 #include "socks.h"
+#include "rtsp.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -226,6 +227,10 @@ static const struct Curl_handler * const
 #endif
 #endif
 
+#ifndef CURL_DISABLE_RTSP
+  &Curl_handler_rtsp,
+#endif
+
   (struct Curl_handler *) NULL
 };
 
@@ -699,6 +704,7 @@ CURLcode Curl_init_userdefined(struct Us
   set->maxredirs = -1;       /* allow any amount by default */
 
   set->httpreq = HTTPREQ_GET; /* Default HTTP request */
+  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
   set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
   set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
   set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
@@ -2323,6 +2329,121 @@ CURLcode Curl_setopt(struct SessionHandl
     data->set.mail_rcpt = va_arg(param, struct curl_slist *);
     break;
 
+  case CURLOPT_RTSP_REQUEST:
+    {
+      /*
+       * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
+       * Would this be better if the RTSPREQ_* were just moved into here?
+       */
+      long curl_rtspreq = va_arg(param, long);
+      long rtspreq = RTSPREQ_NONE;
+      switch(curl_rtspreq) {
+        case CURL_RTSPREQ_OPTIONS:
+          rtspreq = RTSPREQ_OPTIONS;
+          break;
+
+        case CURL_RTSPREQ_DESCRIBE:
+          rtspreq = RTSPREQ_DESCRIBE;
+          break;
+
+        case CURL_RTSPREQ_ANNOUNCE:
+          rtspreq = RTSPREQ_ANNOUNCE;
+          break;
+
+        case CURL_RTSPREQ_SETUP:
+          rtspreq = RTSPREQ_SETUP;
+          break;
+
+        case CURL_RTSPREQ_PLAY:
+          rtspreq = RTSPREQ_PLAY;
+          break;
+
+        case CURL_RTSPREQ_PAUSE:
+          rtspreq = RTSPREQ_PAUSE;
+          break;
+
+        case CURL_RTSPREQ_TEARDOWN:
+          rtspreq = RTSPREQ_TEARDOWN;
+          break;
+
+        case CURL_RTSPREQ_GET_PARAMETER:
+          rtspreq = RTSPREQ_GET_PARAMETER;
+          break;
+
+        case CURL_RTSPREQ_SET_PARAMETER:
+          rtspreq = RTSPREQ_SET_PARAMETER;
+          break;
+
+        case CURL_RTSPREQ_RECORD:
+          rtspreq = RTSPREQ_RECORD;
+          break;
+
+        case CURL_RTSPREQ_RECEIVE:
+          rtspreq = RTSPREQ_RECEIVE;
+          break;
+        default:
+          rtspreq = RTSPREQ_NONE;
+      }
+
+      data->set.rtspreq = rtspreq;
+    break;
+    }
+
+
+  case CURLOPT_RTSP_SESSION_ID:
+    /*
+     * Set the RTSP Session ID manually. Useful if the application is
+     * resuming a previously established RTSP session
+     */
+    result = setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_STREAM_URI:
+    /*
+     * Set the Stream URI for the RTSP request. Unless the request is
+     * for generic server options, the application will need to set this.
+     */
+    result = setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_TRANSPORT:
+    /*
+     * The content of the Transport: header for the RTSP request
+     */
+    result = setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_VERSION:
+    /*
+     * Change the RTSP protocol version
+     */
+    data->set.rtspversion = va_arg(param, long);
+    break;
+
+  case CURLOPT_RTSP_CLIENT_CSEQ:
+    /*
+     * Set the CSEQ number to issue for the next RTSP request. Useful if the
+     * application is resuming a previously broken connection. The CSEQ
+     * will increment from this new number henceforth.
+     */
+    data->state.rtsp_next_client_CSeq = va_arg(param, long);
+    break;
+
+  case CURLOPT_RTSP_SERVER_CSEQ:
+    /* Same as the above, but for server-initiated requests */
+    data->state.rtsp_next_client_CSeq = va_arg(param, long);
+    break;
+
+  case CURLOPT_RTPDATA:
+    data->set.rtp_out = va_arg(param, void *);
+    break;
+  case CURLOPT_RTPFUNCTION:
+    /* Set the user defined RTP write function */
+    data->set.fwrite_rtp = va_arg(param, curl_rtp_write_callback);
+    break;
   default:
     /* unknown tag and its companion, just ignore: */
     result = CURLE_FAILED_INIT; /* correct this */
@@ -2360,6 +2481,7 @@ static void conn_free(struct connectdata
   Curl_safefree(conn->allocptr.ref);
   Curl_safefree(conn->allocptr.host);
   Curl_safefree(conn->allocptr.cookiehost);
+  Curl_safefree(conn->allocptr.rtsp_transport);
   Curl_safefree(conn->trailer);
   Curl_safefree(conn->host.rawalloc); /* host name buffer */
   Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
@@ -2500,6 +2622,42 @@ static bool SocketIsDead(curl_socket_t s
   return ret_val;
 }
 
+#ifndef CURL_DISABLE_RTSP
+/*
+ * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not
+ * want to block the application forever while receiving a stream. Therefore,
+ * we cannot assume that an RTSP socket is dead just because it is readable.
+ *
+ * Instead, if it is readable, run Curl_getconnectinfo() to peek at the socket
+ * and distinguish between closed and data.
+ */
+static bool RTSPConnIsDead(struct connectdata *check)
+{
+  int sval;
+  bool ret_val = TRUE;
+
+  sval = Curl_socket_ready(check->sock[FIRSTSOCKET], CURL_SOCKET_BAD, 0);
+  if(sval == 0) {
+    /* timeout */
+    ret_val = FALSE;
+  }
+  else if (sval & CURL_CSELECT_ERR) {
+    /* socket is in an error state */
+    ret_val = TRUE;
+  }
+  else if (sval & CURL_CSELECT_IN) {
+    /* readable with no error. could be closed or could be alive */
+    long connectinfo = 0;
+    Curl_getconnectinfo(check->data, &connectinfo, &check);
+    if(connectinfo != -1) {
+      ret_val = FALSE;
+    }
+  }
+
+  return ret_val;
+}
+#endif /* CURL_DISABLE_RTSP */
+
 static bool IsPipeliningPossible(const struct SessionHandle *handle)
 {
   if(handle->multi && Curl_multi_canPipeline(handle->multi) &&
@@ -2664,7 +2822,15 @@ ConnectionExists(struct SessionHandle *d
       /* The check for a dead socket makes sense only if there are no
          handles in pipeline and the connection isn't already marked in
          use */
-      bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
+      bool dead;
+#ifndef CURL_DISABLE_RTSP
+      if(check->protocol & PROT_RTSP)
+        /* RTSP is a special case due to RTP interleaving */
+        dead = RTSPConnIsDead(check);
+      else
+#endif /*CURL_DISABLE_RTSP*/
+        dead = SocketIsDead(check->sock[FIRSTSOCKET]);
+
       if(dead) {
         check->data = data;
         infof(data, "Connection #%d seems to be dead!\n", i);
Index: lib/urldata.h
===================================================================
RCS file: /cvsroot/curl/curl/lib/urldata.h,v
retrieving revision 1.430
diff -u -p -r1.430 urldata.h
--- lib/urldata.h	1 Jan 2010 14:52:52 -0000	1.430
+++ lib/urldata.h	14 Jan 2010 18:18:29 -0000
@@ -43,6 +43,7 @@
 #define PORT_POP3S 995
 #define PORT_SMTP 25
 #define PORT_SMTPS 465 /* sometimes called SSMTP */
+#define PORT_RTSP 554
 
 #define DICT_MATCH "/MATCH:"
 #define DICT_MATCH2 "/M:"
@@ -147,6 +148,7 @@
 #include "file.h"
 #include "ssh.h"
 #include "http.h"
+#include "rtsp.h"
 
 #ifdef HAVE_GSSAPI
 # ifdef HAVE_GSSGNU
@@ -510,7 +512,8 @@ struct SingleRequest {
   bool content_range;           /* set TRUE if Content-Range: was found */
   curl_off_t offset;            /* possible resume offset read from the
                                    Content-Range: header */
-  int httpcode;                 /* error code from the 'HTTP/1.? XXX' line */
+  int httpcode;                 /* error code from the 'HTTP/1.? XXX' or
+                                   'RTSP/1.? XXX' line */
   struct timeval start100;      /* time stamp to wait for the 100 code from */
   enum expect100 exp100;        /* expect 100 continue state */
 
@@ -672,8 +675,9 @@ struct connectdata {
 #define PROT_POP3S   CURLPROTO_POP3S
 #define PROT_SMTP    CURLPROTO_SMTP
 #define PROT_SMTPS   CURLPROTO_SMTPS
+#define PROT_RTSP    CURLPROTO_RTSP
 
-/* (1<<17) is currently the highest used bit in the public bitmask. We make
+/* (1<<18) is currently the highest used bit in the public bitmask. We make
    sure we use "private bits" above the public ones to make things easier. */
 
 #define PROT_EXTMASK 0xfffff
@@ -718,7 +722,8 @@ struct connectdata {
   char *proxypasswd;  /* proxy password string, allocated */
   curl_proxytype proxytype; /* what kind of proxy that is in use */
 
-  int httpversion;              /* the HTTP version*10 reported by the server */
+  int httpversion;        /* the HTTP version*10 reported by the server */
+  int rtspversion;        /* the RTSP version*10 reported by the server */
 
   struct timeval now;     /* "current" time */
   struct timeval created; /* creation time */
@@ -750,6 +755,7 @@ struct connectdata {
     char *ref; /* free later if not NULL! */
     char *host; /* free later if not NULL */
     char *cookiehost; /* free later if not NULL */
+    char *rtsp_transport; /* free later if not NULL */
   } allocptr;
 
   int sec_complete; /* if kerberos is enabled for this connection */
@@ -825,6 +831,7 @@ struct connectdata {
     struct imap_conn imapc;
     struct pop3_conn pop3c;
     struct smtp_conn smtpc;
+    struct rtsp_conn rtspc;
   } proto;
 
   int cselect_bits; /* bitmask of socket events */
@@ -844,7 +851,7 @@ struct connectdata {
  * Struct to keep statistical and informational data.
  */
 struct PureInfo {
-  int httpcode;  /* Recent HTTP or FTP response code */
+  int httpcode;  /* Recent HTTP, FTP, or RTSP response code */
   int httpproxycode; /* response code from proxy when received separate */
   int httpversion; /* the http version number X.Y = X*10+Y */
   long filetime; /* If requested, this is might get set. Set to -1 if the time
@@ -915,6 +922,22 @@ typedef enum {
   HTTPREQ_LAST /* last in list */
 } Curl_HttpReq;
 
+typedef enum {
+    RTSPREQ_NONE, /* first in list */
+    RTSPREQ_OPTIONS,
+    RTSPREQ_DESCRIBE,
+    RTSPREQ_ANNOUNCE,
+    RTSPREQ_SETUP,
+    RTSPREQ_PLAY,
+    RTSPREQ_PAUSE,
+    RTSPREQ_TEARDOWN,
+    RTSPREQ_GET_PARAMETER,
+    RTSPREQ_SET_PARAMETER,
+    RTSPREQ_RECORD,
+    RTSPREQ_RECEIVE,
+    RTSPREQ_LAST /* last in list */
+} Curl_RtspReq;
+
 /*
  * Values that are generated, temporary or calculated internally for a
  * "session handle" must be defined within the 'struct UrlState'.  This struct
@@ -1065,6 +1088,11 @@ struct UrlState {
                   this syntax. */
   curl_off_t resume_from; /* continue [ftp] transfer from here */
 
+  /* This RTSP state information survives requests and connections */
+  long rtsp_next_client_CSeq; /* the session's next client CSeq */
+  long rtsp_next_server_CSeq; /* the session's next server CSeq */
+  long rtsp_CSeq_recv; /* most recent CSeq received */
+
   /* Protocol specific data.
    *
    *************************************************************************
@@ -1075,6 +1103,7 @@ struct UrlState {
   union {
     struct HTTP *http;
     struct HTTP *https;  /* alias, just for the sake of being more readable */
+    struct RTSP *rtsp;
     struct FTP *ftp;
     /* void *tftp;    not used */
     struct FILEPROTO *file;
@@ -1125,7 +1154,7 @@ enum dupstring {
   STRING_CERT_TYPE,       /* format for certificate (default: PEM)*/
   STRING_COOKIE,          /* HTTP cookie string to send */
   STRING_COOKIEJAR,       /* dump all cookies to this file */
-  STRING_CUSTOMREQUEST,   /* HTTP/FTP request/method to use */
+  STRING_CUSTOMREQUEST,   /* HTTP/FTP/RTSP request/method to use */
   STRING_DEVICE,          /* local network interface/address to use */
   STRING_ENCODING,        /* Accept-Encoding string */
   STRING_FTP_ACCOUNT,     /* ftp account data */
@@ -1156,6 +1185,9 @@ enum dupstring {
   STRING_PROXYPASSWORD,   /* Proxy <password>, if used */
   STRING_NOPROXY,         /* List of hosts which should not use the proxy, if
                              used */
+  STRING_RTSP_SESSION_ID, /* Session ID to use */
+  STRING_RTSP_STREAM_URI, /* Stream URI for this request */
+  STRING_RTSP_TRANSPORT,  /* Transport for this session */
 #ifdef USE_LIBSSH2
   STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
   STRING_SSH_PUBLIC_KEY,  /* path to the public key file for auth */
@@ -1181,6 +1213,7 @@ struct UserDefined {
   void *out;         /* the fetched file goes here */
   void *in;          /* the uploaded file is read from here */
   void *writeheader; /* write the header to this if non-NULL */
+  void *rtp_out;     /* write RTP to this if non-NULL */
   long use_port;     /* which port to use (when not using default) */
   long httpauth;     /* what kind of HTTP authentication to use (bitmask) */
   long proxyauth;    /* what kind of proxy authentication to use (bitmask) */
@@ -1202,6 +1235,7 @@ struct UserDefined {
                          'localport' one can't be bind()ed */
   curl_write_callback fwrite_func;   /* function that stores the output */
   curl_write_callback fwrite_header; /* function that stores headers */
+  curl_rtp_write_callback fwrite_rtp;    /* function that stores interleaved RTP */
   curl_read_callback fread_func;     /* function that reads the input */
   curl_progress_callback fprogress;  /* function for progress information */
   curl_debug_callback fdebug;      /* function that write informational data */
@@ -1338,6 +1372,9 @@ struct UserDefined {
   long socks5_gssapi_nec; /* flag to support nec socks5 server */
 #endif
   struct curl_slist *mail_rcpt; /* linked list of mail recipients */
+  /* Common RTSP header options */
+  Curl_RtspReq rtspreq; /* RTSP request type */
+  long rtspversion; /* like httpversion, for RTSP */
 };
 
 struct Names {
Index: lib/version.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/version.c,v
retrieving revision 1.62
diff -u -p -r1.62 version.c
--- lib/version.c	12 Dec 2009 21:54:02 -0000	1.62
+++ lib/version.c	14 Jan 2010 18:18:29 -0000
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -143,6 +143,9 @@ static const char * const protocols[] = 
 #ifndef CURL_DISABLE_FILE
   "file",
 #endif
+#ifndef CURL_DISABLE_RTSP
+  "rtsp",
+#endif
 
 #ifdef USE_SSL
 #ifndef CURL_DISABLE_HTTP
