cURL / Mailing Lists / curl-library / Single Mail

curl-library

[telnet] telnet: Allow programatic use of telnet.

From: Ben Greear <greearb_at_candelatech.com>
Date: Wed, 28 Apr 2010 15:49:04 -0700

The main change is to allow input from user-specified methods,
when they are specified with CURLOPT_READFUNCTION.
All calls to fflush(stdout) in telnet.c were removed, which makes
using 'curl telnet://foo.com' painful since prompts and other data
are not always returned to the user promptly. Use
'curl --no-buffer telnet://foo.com' instead. In general,
the user should have their CURLOPT_WRITEFUNCTION do a fflush
for interactive use.

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

Call progress functions in telnet main loop.

Signed-off-by: Ben Greear <greearb_at_candelatech.com>

---
:100644 100644 9409f49... a341b93... M	lib/telnet.c
:100644 100644 357f213... e3d4747... M	lib/url.c
:100644 100644 ad172d6... aab5d23... M	lib/urldata.h
:100644 100644 6e3ef3d... ef53769... M	src/main.c
 lib/telnet.c  |   96 +++++++++++++++++++++++++++++++++++++++++----------------
 lib/url.c     |   14 +++++++-
 lib/urldata.h |    2 +
 src/main.c    |    6 ++-
 4 files changed, 87 insertions(+), 31 deletions(-)
diff --git a/lib/telnet.c b/lib/telnet.c
index 9409f49..a341b93 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>
@@ -962,16 +963,16 @@ CURLcode telrcv(struct connectdata *conn,
   struct SessionHandle *data = conn->data;
   struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
 
-#define startskipping() \
-    if(startwrite >= 0) { \
-       result = Curl_client_write(conn, \
-                                  CLIENTWRITE_BODY, \
-                                  (char *)&inbuf[startwrite], \
-                                  in-startwrite); \
-      if(result != CURLE_OK) \
-        return result; \
-    } \
-    startwrite = -1
+#define startskipping()                                       \
+  if(startwrite >= 0) {                                       \
+    result = Curl_client_write(conn,                          \
+                               CLIENTWRITE_BODY,              \
+                               (char *)&inbuf[startwrite],    \
+                               in-startwrite);                \
+    if(result != CURLE_OK)                                    \
+      return result;                                          \
+  }                                                           \
+  startwrite = -1
 
 #define writebyte() \
     if(startwrite < 0) \
@@ -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 */
 
@@ -1402,8 +1406,6 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
           break;
         }
 
-        fflush(stdout);
-
         /* Negotiate if the peer has started negotiating,
            otherwise don't. We don't want to speak telnet with
            non-telnet servers, like POP or SMTP. */
@@ -1446,27 +1448,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.is_fread_set) {
+    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 +1489,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 +1505,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 +1546,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 357f213..e3d4747 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -690,6 +690,8 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
 
   /* use fread as default function to read input */
   set->fread_func = (curl_read_callback)fread;
+  set->is_fread_set = 0;
+  set->is_fwrite_set = 0;
 
   set->seek_func = ZERO_NULL;
   set->seek_client = ZERO_NULL;
@@ -1825,18 +1827,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
      * Set data write callback
      */
     data->set.fwrite_func = va_arg(param, curl_write_callback);
-    if(!data->set.fwrite_func)
+    if(!data->set.fwrite_func) {
+      data->set.is_fwrite_set = 0;
       /* When set to NULL, reset to our internal default function */
       data->set.fwrite_func = (curl_write_callback)fwrite;
+    }
+    else
+      data->set.is_fwrite_set = 0;
     break;
   case CURLOPT_READFUNCTION:
     /*
      * Read data callback
      */
     data->set.fread_func = va_arg(param, curl_read_callback);
-    if(!data->set.fread_func)
+    if(!data->set.fread_func) {
+      data->set.is_fread_set = 0;
       /* When set to NULL, reset to our internal default function */
       data->set.fread_func = (curl_read_callback)fread;
+    }
+    else
+      data->set.is_fread_set = 1;
     break;
   case CURLOPT_SEEKFUNCTION:
     /*
diff --git a/lib/urldata.h b/lib/urldata.h
index ad172d6..aab5d23 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1234,6 +1234,8 @@ 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 is_fread_set; /* boolean, has read callback been set to non-NULL? */
+  int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */
   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 */
diff --git a/src/main.c b/src/main.c
index 6e3ef3d..ef53769 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4844,8 +4844,10 @@ operate(struct Configurable *config, int argc, argv_item_t argv[])
         input.config = config;
         my_setopt(curl, CURLOPT_READDATA, &input);
         /* what call to read */
-        my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
-
+        if ((outfile && !curlx_strequal("-", outfile)) ||
+            !curlx_strnequal(url, "telnet:", 7))
+          my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
+        
         /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
            CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
         my_setopt(curl, CURLOPT_SEEKDATA, &input);
-- 
1.6.2.5
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2010-04-29