telnet:  Allow programatic use of telnet via libcurl.
  The main change is to allow input from user-specified methods,
  but in order to be backwards compatible, the user also has to set
  the option CURLOPT_FORCE_USE_READFUNC to true.

  Also fix assumption that reading from stdin never returns < 0.
  Old code could crash in that case.

  Call progress functions in telnet main loop.

Patch is attached, please let me know if it needs any improvements.

--
Ben Greear <[email protected]>
Candela Technologies Inc  http://www.candelatech.com
diff --git a/include/curl/curl.h b/include/curl/curl.h
index e635968..c231ca8 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1316,6 +1316,12 @@ typedef enum {
   /* Let the application define a custom write method for RTP data */
   CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196),
 
+  /* Force protocols that normally prefer to use stdin to use
+   * the READFUNCTION.  Useful for programatic use of telnet,
+   * for instance.
+   */
+  CINIT(FORCE_USE_READFUNC, LONG, 197),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
diff --git a/lib/telnet.c b/lib/telnet.c
index 9409f49..e5dc489 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -67,6 +67,7 @@
 #include "sendf.h"
 #include "telnet.h"
 #include "connect.h"
+#include "progress.h"
 
 #define _MPRINTF_REPLACE /* use our functions only */
 #include <curl/mprintf.h>
@@ -1206,6 +1207,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool 
*done)
 #else
   int interval_ms;
   struct pollfd pfd[2];
+  int poll_cnt;
 #endif
   int ret;
   ssize_t nread;
@@ -1213,6 +1215,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool 
*done)
   bool keepon = TRUE;
   char *buf = data->state.buffer;
   struct TELNET *tn;
+  unsigned long total_dl = 0;
+  unsigned long total_ul = 0;
 
   *done = TRUE; /* unconditionally */
 
@@ -1446,27 +1450,28 @@ static CURLcode telnet_do(struct connectdata *conn, 
bool *done)
 #else
   pfd[0].fd = sockfd;
   pfd[0].events = POLLIN;
-  pfd[1].fd = 0;
-  pfd[1].events = POLLIN;
-  interval_ms = 1 * 1000;
+
+  if (data->set.fread_func && data->set.force_use_fread_func) {
+    poll_cnt = 1;
+    interval_ms = 100; /* poll user-supplied read function */
+  }
+  else {
+    pfd[1].fd = 0;
+    pfd[1].events = POLLIN;
+    poll_cnt = 2;
+    interval_ms = 1 * 1000;
+  }
 
   while(keepon) {
-    switch (Curl_poll(pfd, 2, interval_ms)) {
+    switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
     case -1:                    /* error, stop reading */
       keepon = FALSE;
       continue;
     case 0:                     /* timeout */
-      break;
+      pfd[0].revents = 0;
+      pfd[1].revents = 0;
+      /* fall through */
     default:                    /* read! */
-      if(pfd[1].revents & POLLIN) { /* read from stdin */
-        nread = read(0, buf, 255);
-        code = send_telnet_data(conn, buf, nread);
-        if(code) {
-          keepon = FALSE;
-          break;
-        }
-      }
-
       if(pfd[0].revents & POLLIN) {
         /* read data from network */
         ret = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
@@ -1486,6 +1491,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool 
*done)
           break;
         }
 
+        total_dl += nread;
+        Curl_pgrsSetDownloadCounter(data, total_dl);        
         code = telrcv(conn, (unsigned char *)buf, nread);
         if(code) {
           keepon = FALSE;
@@ -1500,7 +1507,39 @@ static CURLcode telnet_do(struct connectdata *conn, bool 
*done)
           tn->already_negotiated = 1;
         }
       }
-    }
+
+      nread = 0;
+      if (poll_cnt == 2) {
+        if(pfd[1].revents & POLLIN) { /* read from stdin */
+          nread = read(0, buf, BUFSIZE - 1);
+        }
+      }
+      else {
+        /* read from user-supplied method */
+        nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
+        if (nread == CURL_READFUNC_ABORT) {
+          keepon = FALSE;
+          break;
+        }
+        if (nread == CURL_READFUNC_PAUSE)
+          break;
+      }
+        
+      if (nread > 0) {        
+        code = send_telnet_data(conn, buf, nread);
+        if(code) {
+          keepon = FALSE;
+          break;
+        }
+        total_ul += nread;
+        Curl_pgrsSetUploadCounter(data, total_ul);
+      }
+      else if (nread < 0) {
+        keepon = FALSE;
+      }
+      break;
+    }/* poll switch statement */
+    
     if(data->set.timeout) {
       now = Curl_tvnow();
       if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
@@ -1509,6 +1548,11 @@ static CURLcode telnet_do(struct connectdata *conn, bool 
*done)
         keepon = FALSE;
       }
     }
+
+    if(Curl_pgrsUpdate(conn)) {
+       code = CURLE_ABORTED_BY_CALLBACK;
+       break;
+    }
   }
 #endif
   /* mark this as "no further transfer wanted" */
diff --git a/lib/url.c b/lib/url.c
index e32e8da..bd9bd46 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1838,6 +1838,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, 
CURLoption option,
       /* When set to NULL, reset to our internal default function */
       data->set.fread_func = (curl_read_callback)fread;
     break;
+  case CURLOPT_FORCE_USE_READFUNC:
+    data->set.force_use_fread_func = va_arg(param, long);
+    break;
   case CURLOPT_SEEKFUNCTION:
     /*
      * Seek callback. Might be NULL.
diff --git a/lib/urldata.h b/lib/urldata.h
index f6b8de9..f85face 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1234,6 +1234,9 @@ struct UserDefined {
   curl_write_callback fwrite_header; /* function that stores headers */
   curl_write_callback fwrite_rtp;    /* function that stores interleaved RTP */
   curl_read_callback fread_func;     /* function that reads the input */
+  int force_use_fread_func; /* boolean, should we use read-func in protocols
+                             * that normally don't (like telnet)?
+                             */
   curl_progress_callback fprogress;  /* function for progress information */
   curl_debug_callback fdebug;      /* function that write informational data */
   curl_ioctl_callback ioctl_func;  /* function for I/O control */
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html

Reply via email to