--- doc/chan.n.orig	2006-10-28 22:37:48.000000000 -0600
+++ doc/chan.n	2006-10-28 22:51:33.000000000 -0600
@@ -24,6 +24,14 @@
 \fIOption\fR indicates what to do with the channel; any unique
 abbreviation for \fIoption\fR is acceptable. Valid options are:
 .TP
+\fBchan available \fIchannelId\fR
+.
+This returns the number of bytes of input currently buffered 
+internally for \fIchannelId\fr (especially useful in a readable event 
+callback to impose application-specific limits on line lengths to avoid
+a potential denial-of-service attack where a hostile user crafts
+an extremely long line that exceeds the available memory to buffer it).
+.TP
 \fBchan blocked \fIchannelId\fR
 .
 This tests whether the last input operation on the channel called
--- generic/tclBasic.c.orig	2006-10-28 21:55:59.000000000 -0600
+++ generic/tclBasic.c	2006-10-28 21:57:08.000000000 -0600
@@ -485,6 +485,10 @@
     Tcl_CreateObjCommand(interp, "::tcl::chan::rPostevent",
 	    TclChanPostEventObjCmd, (ClientData) NULL, NULL);
 
+    /* TIP #287 */
+    Tcl_CreateObjCommand(interp, "::tcl::chan::Available",
+	    TclChanAvailableObjCmd, (ClientData) NULL, NULL);
+
     /*
      * Register the built-in functions. This is empty now that they are
      * implemented as commands in the ::tcl::mathfunc namespace.
--- generic/tclInt.h.orig	2006-10-28 22:08:38.000000000 -0600
+++ generic/tclInt.h	2006-10-28 22:09:52.000000000 -0600
@@ -2286,6 +2286,9 @@
 MODULE_SCOPE int	Tcl_CdObjCmd(ClientData clientData,
 			    Tcl_Interp *interp, int objc,
 			    Tcl_Obj *CONST objv[]);
+MODULE_SCOPE int	TclChanAvailableObjCmd(
+			    ClientData clientData, Tcl_Interp *interp,
+			    int objc, Tcl_Obj *CONST objv[]);
 MODULE_SCOPE int	TclChanTruncateObjCmd(
 			    ClientData clientData, Tcl_Interp *interp,
 			    int objc, Tcl_Obj *CONST objv[]);
--- generic/tclIOCmd.c.orig	2006-10-28 21:58:27.000000000 -0600
+++ generic/tclIOCmd.c	2006-10-28 22:08:03.000000000 -0600
@@ -1619,6 +1619,56 @@
 }
 
 /*
+ *---------------------------------------------------------------------------
+ *
+ * TclChanAvailableObjCmd --
+ *
+ *	This function is invoked to process the Tcl "chan available" 
+ *	command. See the user documentation for details on what it does.
+ *
+ * Results:
+ *	A standard Tcl result.
+ *
+ * Side effects:
+ *	Sets interp's result to the number of bytes of input in the
+ *      channels input buffer.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+	/* ARGSUSED */
+int
+TclChanAvailableObjCmd(
+    ClientData unused,		/* Not used. */
+    Tcl_Interp *interp,		/* Current interpreter. */
+    int objc,			/* Number of arguments. */
+    Tcl_Obj *CONST objv[])	/* Argument objects. */
+{
+    Tcl_Channel chan;
+    int mode;
+    char *arg;
+
+    if (objc != 2) {
+	Tcl_WrongNumArgs(interp, 1, objv, "channelId");
+	return TCL_ERROR;
+    }
+
+    arg = Tcl_GetString(objv[1]);
+    chan = Tcl_GetChannel(interp, arg, &mode);
+    if (chan == NULL) {
+	return TCL_ERROR;
+    }
+    if ((mode & TCL_READABLE) == 0) {
+	Tcl_AppendResult(interp, "channel \"", arg,
+		"\" wasn't opened for reading", NULL);
+	return TCL_ERROR;
+    }
+
+    Tcl_SetObjResult(interp, Tcl_NewIntObj(Tcl_InputBuffered(chan)));
+    return TCL_OK;
+}
+
+/*
  *----------------------------------------------------------------------
  *
  * Tcl_ChanTruncateObjCmd --
--- library/init.tcl.orig	2006-09-22 12:13:29.000000000 -0600
+++ library/init.tcl	2006-10-28 21:55:41.000000000 -0600
@@ -78,7 +78,9 @@
     # Set up the 'chan' ensemble (TIP #208).
     namespace eval chan {
         # TIP #219. Added methods: create, postevent.
+        # TIP #287. Added method: available.
         namespace ensemble create -command ::chan -map {
+            available   ::tcl::chan::Available
             blocked     ::fblocked
             close       ::close
             configure   ::fconfigure
--- tests/chan.test.orig	2006-10-29 13:59:35.000000000 -0700
+++ tests/chan.test	2006-10-29 14:22:51.000000000 -0700
@@ -24,7 +24,7 @@
 } -returnCodes error -result "wrong # args: should be \"chan subcommand ?argument ...?\""
 test chan-1.2 {chan command general syntax} -body {
     chan FOOBAR
-} -returnCodes error -result "unknown or ambiguous subcommand \"FOOBAR\": must be blocked, close, configure, copy, create, eof, event, flush, gets, names, postevent, puts, read, seek, tell, or truncate"
+} -returnCodes error -result "unknown or ambiguous subcommand \"FOOBAR\": must be available, blocked, close, configure, copy, create, eof, event, flush, gets, names, postevent, puts, read, seek, tell, or truncate"
 
 test chan-2.1 {chan command: blocked subcommand} -body {
     chan blocked foo bar
@@ -96,6 +96,35 @@
     catch {removeFile $file}
 }
 
+# TIP 287: chan available
+test chan-16.1 {chan command: available subcommand} -body {
+    chan available foo bar
+} -returnCodes error -result "wrong # args: should be \"chan available channelId\""
+test chan-16.2 {chan command: available subcommand} -body {
+    chan available stdout 
+} -returnCodes error -result "channel \"stdout\" wasn't opened for reading"
+test chan-16.3 {chan command: available subcommand} -body {
+    chan available stdin
+} -result 0
+test chan-16.4 {chan command: available subcommand} -body {
+    chan available FOOBAR
+} -returnCodes error -result "can not find channel named \"FOOBAR\""
+test chan-16.5 {chan command: available subcommand} -setup {
+    set file [makeFile {} testAvailable]
+    set f [open $file w+]
+    chan configure $f -translation lf -buffering line
+} -body {
+    chan puts $f foo
+    chan puts $f bar
+    chan puts $f baz
+    chan seek $f 0
+    chan gets $f
+    chan available $f
+} -result 8 -cleanup {
+    catch {chan close $f}
+    catch {removeFile $file}
+}
+
 cleanupTests
 return
 
--- tests/ioCmd.test.orig	2006-10-28 23:06:44.000000000 -0600
+++ tests/ioCmd.test	2006-10-28 23:09:10.000000000 -0600
@@ -628,7 +628,7 @@
 test iocmd-20.1 {chan, unknown method} {
     catch {chan foo} msg
     set msg
-} {unknown or ambiguous subcommand "foo": must be blocked, close, configure, copy, create, eof, event, flush, gets, names, postevent, puts, read, seek, tell, or truncate}
+} {unknown or ambiguous subcommand "foo": must be available, blocked, close, configure, copy, create, eof, event, flush, gets, names, postevent, puts, read, seek, tell, or truncate}
 
 # --- --- --- --------- --------- ---------
 # chan create, and method "initalize"
