summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDominik Picheta <dominikpicheta@googlemail.com>2015-07-01 21:05:45 +0100
committerDominik Picheta <dominikpicheta@googlemail.com>2015-07-01 21:05:45 +0100
commitcb5d090cdb0318542804df7f122475b7de5410a6 (patch)
tree88f3cee7fec5852a2f07b7eb9165f511c5041fba
parentd67e93340a30060fc7d2088f7d2e11d17079a83d (diff)
downloadNim-cb5d090cdb0318542804df7f122475b7de5410a6.tar.gz
Moved handling of multi-line FTP replies to `expectReply`.
-rw-r--r--lib/pure/asyncftpclient.nim19
-rw-r--r--lib/pure/ftpclient.nim19
2 files changed, 30 insertions, 8 deletions
diff --git a/lib/pure/asyncftpclient.nim b/lib/pure/asyncftpclient.nim
index ff98d94c1..fe4577ed9 100644
--- a/lib/pure/asyncftpclient.nim
+++ b/lib/pure/asyncftpclient.nim
@@ -37,12 +37,24 @@ type
     proc (total, progress: BiggestInt, speed: float):
       Future[void] {.closure, gcsafe.}
 
-proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] =
-  result = ftp.csock.recvLine()
+const multiLineLimit = 10000
+
+proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] {.async.} =
+  result = await ftp.csock.recvLine()
+  var count = 0
+  while result[3] == '-':
+    ## Multi-line reply.
+    let line = await ftp.csock.recvLine()
+    result.add("\n" & line)
+    count.inc()
+    if count >= multiLineLimit:
+      raise newException(ReplyError, "Reached maximum multi-line reply count.")
 
 proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} =
   ## Send a message to the server, and wait for a primary reply.
   ## ``\c\L`` is added for you.
+  ##
+  ## **Note:** The server may return multiple lines of coded replies.
   await ftp.csock.send(m & "\c\L")
   return await ftp.expectReply()
 
@@ -82,9 +94,6 @@ proc connect*(ftp: AsyncFtpClient) {.async.} =
 
   # Handle 220 messages from the server
   assertReply(reply, "220")
-  while reply[3] == "-": # handle multiline 220 message
-    assertReply(reply, "220")
-    reply = await ftp.expectReply()
 
   if ftp.user != "":
     assertReply(await(ftp.send("USER " & ftp.user)), "230", "331")
diff --git a/lib/pure/ftpclient.nim b/lib/pure/ftpclient.nim
index 2644fc010..778ba6857 100644
--- a/lib/pure/ftpclient.nim
+++ b/lib/pure/ftpclient.nim
@@ -107,6 +107,8 @@ type
   EInvalidReply: ReplyError, EFTP: FTPError
 ].}
 
+const multiLineLimit = 10000
+
 proc ftpClient*(address: string, port = Port(21),
                 user, pass = ""): FtpClient =
   ## Create a ``FtpClient`` object.
@@ -135,10 +137,24 @@ proc expectReply[T](ftp: FtpBase[T]): TaintedString =
       ftp.csock.readLine(result)
     else:
       discard ftp.csock.readLine(result)
+    var count = 0
+    while result[3] == '-':
+      ## Multi-line reply.
+      var line = TaintedString""
+      when T is Socket:
+        ftp.csock.readLine(line)
+      else:
+        discard ftp.csock.readLine(line)
+      result.add("\n" & line)
+      count.inc()
+      if count >= multiLineLimit:
+        raise newException(ReplyError, "Reached maximum multi-line reply count.")
 
 proc send*[T](ftp: FtpBase[T], m: string): TaintedString =
   ## Send a message to the server, and wait for a primary reply.
   ## ``\c\L`` is added for you.
+  ##
+  ## **Note:** The server may return multiple lines of coded replies.
   blockingOperation(ftp.csock):
     ftp.csock.send(m & "\c\L")
   return ftp.expectReply()
@@ -271,9 +287,6 @@ proc connect*[T](ftp: FtpBase[T]) =
 
   # Handle 220 messages from the server
   assertReply ftp.expectReply(), "220"
-  while reply[3] == "-": # handle multiline 220 message
-    assertReply ftp.expectReply(), "220"
-    reply = ftp.expectReply()
 
   if ftp.user != "":
     assertReply(ftp.send("USER " & ftp.user), "230", "331")
od programming language, which combines Lisp's power with Python's readability and C's performance.** Welcome to Nimrod ----------------- **Nimrod** is a new statically typed, imperative programming language, that supports procedural, object oriented, functional and generic programming styles while remaining simple and efficient. A special feature that Nimrod inherited from Lisp is that Nimrod's abstract syntax tree (*AST*) is part of the specification - this allows a powerful macro system which allows domain specific languages. Nimrod is a compiled, garbage-collected systems programming language which has an excellent productivity/performance ratio. Nimrod's design focuses on the 3E: efficiency, expressiveness, elegance (in the order of priority). .. container:: snippet *Nimrod looks like this:* .. code-block:: nimrod import strutils echo "Type in a list of ints of ints (separate by whitespace): " let tokens = stdin.readLine.split echo tokens.each(parseInt).max, " is the maximum." Nimrod is efficient =================== * Native code generation (currently via compilation to C), not dependent on a virtual machine: **Nimrod produces small executables without dependencies for easy redistribution.** * A fast **non-tracing** garbage collector that supports soft real-time systems (like games). * System programming features: Ability to manage your own memory and access the hardware directly. Pointers to garbage collected memory are distinguished from pointers to manually managed memory. * Zero-overhead iterators. * Cross-module inlining. * Dynamic method binding with inlining and without virtual method table. * Compile time evaluation of user-defined functions. * Whole program dead code elimination: Only *used functions* are included in the executable. * Value-based datatypes: For instance, objects and arrays can be allocated on the stack. Nimrod is expressive ==================== * **The Nimrod compiler and all of the standard library are implemented in Nimrod.** * Built-in high level datatypes: strings, sets, sequences, etc. * Modern type system with local type inference, tuples, variants, generics, etc. * User-defineable operators; code with new operators is often easier to read than code which overloads built-in operators. For example, a ``=~`` operator is defined in the ``re`` module. * Macros can modify the abstract syntax tree at compile time. Nimrod is elegant ================= * Macros can use the imperative paradigm to construct parse trees. Nimrod does not require a different coding style for meta programming. * Macros cannot change Nimrod's syntax because there is no need for it. Nimrod's syntax is flexible enough. * Statements are grouped by indentation but can span multiple lines. Indentation must not contain tabulators so the compiler always sees the code the same way as you do. Nimrod plays nice with others ============================= * The Nimrod Compiler runs on Windows, Linux, BSD and Mac OS X. Porting to other platforms is easy. * **The Nimrod Compiler can also generate C++ or Objective C for easier interfacing.** * There are lots of bindings: for example, bindings to GTK2, the Windows API, the POSIX API, OpenGL, SDL, Cario, Python, Lua, TCL, X11, libzip, PCRE, libcurl, mySQL and SQLite are included in the standard distribution. * A C to Nimrod conversion utility: New bindings to C libraries are easily generated by ``c2nim``. Roadmap to 1.0 ============== Version 0.9.x * first class iterators * 2-phase type system for better interaction between macros, templates and overloading * the syntactic distinction between statements and expressions will be removed * the binding rules for generics and templates will change * exception tracking * the effect system will be extended * the need for forward declarations may be removed