/**
  * login using supplied user/pwd. Note that login must be the first command if used
  *
  * @param user username
  * @param pwd password
  * @return returns <code>true</code> on success
  */
 public void login(String user, String pwd) throws RSrvException {
   if (!authReq) return;
   if (!connected || rt == null) throw new RSrvException(this, "Not connected");
   if (authType == AT_crypt) {
     if (Key == null) Key = "rs";
     Rpacket rp = rt.request(Rtalk.CMD_login, user + "\n" + jcrypt.crypt(Key, pwd));
     if (rp != null && rp.isOk()) return;
     try {
       s.close();
     } catch (Exception e) {
     }
     ;
     is = null;
     os = null;
     s = null;
     connected = false;
     throw new RSrvException(this, "login failed", rp);
   }
   Rpacket rp = rt.request(Rtalk.CMD_login, user + "\n" + pwd);
   if (rp != null && rp.isOk()) return;
   try {
     s.close();
   } catch (Exception e) {
   }
   ;
   is = null;
   os = null;
   s = null;
   connected = false;
   throw new RSrvException(this, "login failed", rp);
 }
  /**
   * shutdown remote Rserv. Note that some Rserves cannot be shut down from client side (forked
   * version).
   */
  public void shutdown() throws RSrvException {
    if (!connected || rt == null) throw new RSrvException(this, "Not connected");

    Rpacket rp = rt.request(Rtalk.CMD_shutdown);
    if (rp != null && rp.isOk()) return;
    throw new RSrvException(this, "shutdown failed", rp);
  }
  /**
   * Sets send buffer size of the Rserve (in bytes) for the current connection. All responses send
   * by Rserve are stored in the send buffer before transmitting. This means that any objects you
   * want to get from the Rserve need to fit into that buffer. By default the size of the send
   * buffer is 2MB. If you need to receive larger objects from Rserve, you will need to use this
   * function to enlarge the buffer. In order to save memory, you can also reduce the buffer size
   * once it's not used anymore. Currently the buffer size is only limited by the memory available
   * and/or 1GB (whichever is smaller). Current Rserve implementations won't go below buffer sizes
   * of 32kb though. If the specified buffer size results in 'out of memory' on the server, the
   * corresponding error is sent and the connection is terminated.<br>
   * <i>Note:</i> This command may go away in future versions of Rserve which will use dynamic send
   * buffer allocation.
   *
   * @param sbs send buffer size (in bytes) min=32k, max=1GB
   */
  public void setSendBufferSize(long sbs) throws RSrvException {
    if (!connected || rt == null) throw new RSrvException(this, "Not connected");

    Rpacket rp = rt.request(Rtalk.CMD_setBufferSize, (int) sbs);
    if (rp != null && rp.isOk()) return;
    throw new RSrvException(this, "setSendBufferSize failed", rp);
  }
 /**
  * assign a string value to a symbol in R. The symbol is created if it doesn't exist already.
  *
  * @param sym symbol name. Currently assign uses CMD_setSEXP command of Rserve, i.e. the symbol
  *     value is NOT parsed. It is the responsibility of the user to make sure that the symbol name
  *     is valid in R (recall the difference between a symbol and an expression!). In fact R will
  *     always create the symbol, but it may not be accessible (examples: "bar\nfoo" or "bar$foo").
  * @param ct contents
  * @return <code>true</code> on success, otherwise <code>false</code>
  */
 public void assign(String sym, String ct) throws RSrvException {
   if (!connected || rt == null) throw new RSrvException(this, "Not connected");
   byte[] symn = sym.getBytes();
   byte[] ctn = ct.getBytes();
   int sl = symn.length + 1;
   int cl = ctn.length + 1;
   if ((sl & 3) > 0) sl = (sl & 0xfffffc) + 4; // make sure the symbol length is divisible by 4
   if ((cl & 3) > 0) cl = (cl & 0xfffffc) + 4; // make sure the content length is divisible by 4
   byte[] rq = new byte[sl + 4 + cl + 4];
   int ic;
   for (ic = 0; ic < symn.length; ic++) rq[ic + 4] = symn[ic];
   while (ic < sl) {
     rq[ic + 4] = 0;
     ic++;
   }
   for (ic = 0; ic < ctn.length; ic++) rq[ic + sl + 8] = ctn[ic];
   while (ic < cl) {
     rq[ic + sl + 8] = 0;
     ic++;
   }
   Rtalk.setHdr(Rtalk.DT_STRING, sl, rq, 0);
   Rtalk.setHdr(Rtalk.DT_STRING, cl, rq, sl + 4);
   Rpacket rp = rt.request(Rtalk.CMD_setSEXP, rq);
   if (rp != null && rp.isOk()) return;
   throw new RSrvException(this, "assign failed", rp);
 }
 /**
  * detaches the session and closes the connection (requires Rserve 0.4+). The session can be only
  * resumed by calling @link{RSession.attach}
  */
 public RSession detach() throws RSrvException {
   if (!connected || rt == null) throw new RSrvException(this, "Not connected");
   Rpacket rp = rt.request(Rtalk.CMD_detachSession);
   if (rp == null || !rp.isOk()) throw new RSrvException(this, "Cannot detach", rp);
   RSession s = new RSession(this, rp);
   close();
   return s;
 }
 /**
  * evaluates the given command, detaches the session (see @link{detach()}) and closes connection
  * while the command is being evaluted (requires Rserve 0.4+). Note that a session cannot be
  * attached again until the commad was successfully processed. Techincally the session is put into
  * listening mode while the command is being evaluated but accept is called only after the command
  * was evaluated. One commonly used techique to monitor detached working sessions is to use second
  * connection to poll the status (e.g. create a temporary file and return the full path before
  * detaching thus allowing new connections to read it).
  *
  * @param cmd command/expression string
  * @return session object that can be use to attach back to the session once the command completed
  */
 public RSession voidEvalDetach(String cmd) throws RSrvException {
   if (!connected || rt == null) throw new RSrvException(this, "Not connected");
   Rpacket rp = rt.request(Rtalk.CMD_detachedVoidEval, cmd + "\n");
   if (rp == null || !rp.isOk()) throw new RSrvException(this, "detached void eval failed", rp);
   RSession s = new RSession(this, rp);
   close();
   return s;
 }
 REXP parseEvalResponse(Rpacket rp) throws RSrvException {
   int rxo = 0;
   byte[] pc = rp.getCont();
   if (rsrvVersion > 100) {
       /* since 0101 eval responds correctly by using DT_SEXP type/len header which is 4 bytes long */
     rxo = 4;
     /* we should check parameter type (should be DT_SEXP) and fail if it's not */
     if (pc[0] != Rtalk.DT_SEXP && pc[0] != (Rtalk.DT_SEXP | Rtalk.DT_LARGE))
       throw new RSrvException(
           this,
           "Error while processing eval output: SEXP (type "
               + Rtalk.DT_SEXP
               + ") expected but found result type "
               + pc[0]
               + ".");
     if (pc[0] == (Rtalk.DT_SEXP | Rtalk.DT_LARGE)) rxo = 8; // large data need skip of 8 bytes
     /* warning: we are not checking or using the length - we assume that only the one SEXP is returned. This is true for the current CMD_eval implementation, but may not be in the future. */
   }
   REXP rx = null;
   if (pc.length > rxo) {
     rx = new REXP();
     REXP.parseREXP(rx, pc, rxo);
   }
   return rx;
 }
 /**
  * assign a content of a REXP to a symbol in R. The symbol is created if it doesn't exist already.
  *
  * @param sym symbol name. Currently assign uses CMD_setSEXP command of Rserve, i.e. the symbol
  *     value is NOT parsed. It is the responsibility of the user to make sure that the symbol name
  *     is valid in R (recall the difference between a symbol and an expression!). In fact R will
  *     always create the symbol, but it may not be accessible (examples: "bar\nfoo" or "bar$foo").
  * @param ct contents. currently only basic types (int, double, int[], double[]) are supported.
  * @return <code>true</code> on success, otherwise <code>false</code>
  */
 public void assign(String sym, REXP r) throws RSrvException {
   if (!connected || rt == null) throw new RSrvException(this, "Not connected");
   int rl = r.getBinaryLength();
   byte[] symn = sym.getBytes();
   int sl = symn.length + 1;
   if ((sl & 3) > 0) sl = (sl & 0xfffffc) + 4; // make sure the symbol length is divisible by 4
   byte[] rq = new byte[sl + rl + ((rl > 0xfffff0) ? 12 : 8)];
   int ic;
   for (ic = 0; ic < symn.length; ic++) rq[ic + 4] = symn[ic];
   while (ic < sl) {
     rq[ic + 4] = 0;
     ic++;
   }
   ; // pad with 0
   Rtalk.setHdr(Rtalk.DT_STRING, sl, rq, 0);
   Rtalk.setHdr(Rtalk.DT_SEXP, rl, rq, sl + 4);
   r.getBinaryRepresentation(rq, sl + ((rl > 0xfffff0) ? 12 : 8));
   Rpacket rp = rt.request(Rtalk.CMD_setSEXP, rq);
   if (rp != null && rp.isOk()) return;
   throw new RSrvException(this, "assign failed", rp);
 }
 /**
  * remove a file on the Rserve
  *
  * @param fn file name. should not contain any path delimiters, since Rserve may restrict the
  *     access to local working directory.
  * @return <code>true</code> on success, <code>false</code> otherwise
  */
 public void removeFile(String fn) throws RSrvException {
   if (!connected || rt == null) throw new RSrvException(this, "Not connected");
   Rpacket rp = rt.request(Rtalk.CMD_removeFile, fn);
   if (rp != null && rp.isOk()) return;
   throw new RSrvException(this, "removeFile failed", rp);
 }
 /**
  * evaluates the given command and retrieves the result
  *
  * @param cmd command/expression string
  * @return R-xpression or <code>null</code> if an error occured
  */
 public REXP eval(String cmd) throws RSrvException {
   if (!connected || rt == null) throw new RSrvException(this, "Not connected");
   Rpacket rp = rt.request(Rtalk.CMD_eval, cmd + "\n");
   if (rp != null && rp.isOk()) return parseEvalResponse(rp);
   throw new RSrvException(this, "eval failed", rp);
 }
 /**
  * evaluates the given command, but does not fetch the result (useful for assignment operations)
  *
  * @param cmd command/expression string
  * @return <code>true</code> if successful
  */
 public void voidEval(String cmd) throws RSrvException {
   if (!connected || rt == null) throw new RSrvException(this, "Not connected");
   Rpacket rp = rt.request(Rtalk.CMD_voidEval, cmd + "\n");
   if (rp != null && rp.isOk()) return;
   throw new RSrvException(this, "voidEval failed", rp);
 }