Open Source Repository

Home /mail/mail-1.4.1 | Repository Home



com/sun/mail/iap/Argument.java
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

/*
 * @(#)Argument.java  1.11 07/05/04
 */

package com.sun.mail.iap;

import java.util.Vector;
import java.io.*;
import com.sun.mail.util.*;

/**
 @version 1.11, 07/05/04
 @author  John Mani
 */

public class Argument {
    protected Vector items;

    /**
     * Constructor
     */
    public Argument() {
  items = new Vector(1);
    }

    /**
     * append the given Argument to this Argument. All items
     * from the source argument are copied into this destination
     * argument.
     */
    public void append(Argument arg) {
  items.ensureCapacity(items.size() + arg.items.size());
  for (int i=0; i < arg.items.size(); i++)
      items.addElement(arg.items.elementAt(i));
    }

    /**
     * Write out given string as an ASTRING, depending on the type
     * of the characters inside the string. The string should
     * contain only ASCII characters. <p>
     *
     * XXX: Hmm .. this should really be called writeASCII()
     *
     @param s  String to write out
     */
    public void writeString(String s) {
  items.addElement(new AString(ASCIIUtility.getBytes(s)));
    }

    /**
     * Convert the given string into bytes in the specified
     * charset, and write the bytes out as an ASTRING
     */
    public void writeString(String s, String charset)
    throws UnsupportedEncodingException {
  if (charset == null// convenience
      writeString(s);
  else
      items.addElement(new AString(s.getBytes(charset)));
    }

    /**
     * Write out given byte[] as a Literal.
     @param b  byte[] to write out
     */
    public void writeBytes(byte[] b)  {
  items.addElement(b);
    }

    /**
     * Write out given ByteArrayOutputStream as a Literal.
     @param b  ByteArrayOutputStream to be written out.
     */
    public void writeBytes(ByteArrayOutputStream b)  {
  items.addElement(b);
    }

    /**
     * Write out given data as a literal.
     @param b  Literal representing data to be written out.
     */
    public void writeBytes(Literal b)  {
  items.addElement(b);
    }

    /**
     * Write out given string as an Atom. Note that an Atom can contain only
     * certain US-ASCII characters.  No validation is done on the characters 
     * in the string.
     @param s  String
     */
    public void writeAtom(String s) {
  items.addElement(new Atom(s));
    }

    /**
     * Write out number.
     @param i number
     */
    public void writeNumber(int i) {
  items.addElement(new Integer(i));
    }

    /**
     * Write out number.
     @param i number
     */
    public void writeNumber(long i) {
  items.addElement(new Long(i));
    }

    /**
     * Write out as parenthesised list.
     @param s statement
     */
    public void writeArgument(Argument c) {
  items.addElement(c);
    }

    /*
     * Write out all the buffered items into the output stream.
     */
    public void write(Protocol protocol
    throws IOException, ProtocolException {
  int size = items != null ? items.size() 0;
  DataOutputStream os = (DataOutputStream)protocol.getOutputStream();

  for (int i=0; i < size; i++) {
      if (i > 0)  // write delimiter if not the first item
    os.write(' ');

      Object o = items.elementAt(i);
      if (instanceof Atom) {
    os.writeBytes(((Atom)o).string);
      else if (instanceof Number) {
    os.writeBytes(((Number)o).toString());
      else if (instanceof AString) {
    astring(((AString)o).bytes, protocol);
      else if (instanceof byte[]) {
    literal((byte[])o, protocol);
      else if (instanceof ByteArrayOutputStream) {
    literal((ByteArrayOutputStream)o, protocol);
      else if (instanceof Literal) {
    literal((Literal)o, protocol);
      else if (instanceof Argument) {
    os.write('(')// open parans
    ((Argument)o).write(protocol);
    os.write(')')// close parans
      }
  }
    }

    /**
     * Write out given String as either an Atom, QuotedString or Literal
     */
    private void astring(byte[] bytes, Protocol protocol
      throws IOException, ProtocolException {
  DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
  int len = bytes.length;

  // If length is greater than 1024 bytes, send as literal
  if (len > 1024) {
      literal(bytes, protocol);
      return;
  }

        // if 0 length, send as quoted-string
        boolean quote = len == truefalse;
  boolean escape = false;
   
  byte b;
  for (int i = 0; i < len; i++) {
      b = bytes[i];
      if (b == '\0' || b == '\r' || b == '\n' || ((b & 0xff0177)) {
    // NUL, CR or LF means the bytes need to be sent as literals
    literal(bytes, protocol);
    return;
      }
      if (b == '*' || b == '%' || b == '(' || b == ')' || b == '{' ||
    b == '"' || b == '\\' || ((b & 0xff<= ' ')) {
    quote = true;
    if (b == '"' || b == '\\'// need to escape these characters
        escape = true;
      }
  }

  if (quote// start quote
      os.write('"');

        if (escape) {
            // already quoted
            for (int i = 0; i < len; i++) {
                b = bytes[i];
                if (b == '"' || b == '\\')
                    os.write('\\');
                os.write(b);
            }
        else 
            os.write(bytes);
 

  if (quote// end quote
      os.write('"');
    }

    /**
     * Write out given byte[] as a literal
     */
    private void literal(byte[] b, Protocol protocol
      throws IOException, ProtocolException {
  startLiteral(protocol, b.length).write(b);
    }

    /**
     * Write out given ByteArrayOutputStream as a literal.
     */
    private void literal(ByteArrayOutputStream b, Protocol protocol
      throws IOException, ProtocolException {
  b.writeTo(startLiteral(protocol, b.size()));
    }

    /**
     * Write out given Literal as a literal.
     */
    private void literal(Literal b, Protocol protocol
      throws IOException, ProtocolException {
  b.writeTo(startLiteral(protocol, b.size()));
    }

    private OutputStream startLiteral(Protocol protocol, int size
      throws IOException, ProtocolException {
  DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
  boolean nonSync = protocol.supportsNonSyncLiterals();

  os.write('{');
  os.writeBytes(Integer.toString(size));
  if (nonSync// server supports non-sync literals
      os.writeBytes("+}\r\n");
  else
      os.writeBytes("}\r\n");
  os.flush();

  // If we are using synchronized literals, wait for the server's
  // continuation signal
  if (!nonSync) {
      for (; ;) {
    Response r = protocol.readResponse();
    if (r.isContinuation())
        break;
    if (r.isTagged())
        throw new LiteralException(r);
    // XXX - throw away untagged responses;
    //   violates IMAP spec, hope no servers do this
      }
  }
  return os;
    }
}

class Atom {
    String string;

    Atom(String s) {
  string = s;
    }
}

class AString {
    byte[] bytes;

    AString(byte[] b) {
  bytes = b;
    }
}