/*
* Funambol is a mobile platform developed by Funambol, Inc.
* Copyright (C) 2007 Funambol, Inc.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE
* WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program; if not, see http://www.gnu.org/licenses or write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*
* You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite
* 305, Redwood City, CA 94063, USA, or at email address info@funambol.com.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License
* version 3, these Appropriate Legal Notices must retain the display of the
* "Powered by Funambol" logo. If the display of the logo is not reasonably
* feasible for technical reasons, the Appropriate Legal Notices must display
* the words "Powered by Funambol".
*/
package com.funambol.common.pim.model.converter;
import com.funambol.common.pim.model.model.Parameter;
import com.funambol.common.pim.model.model.Property;
import com.funambol.common.pim.model.model.VCalendar;
import com.funambol.common.pim.model.model.VComponent;
import java.util.Iterator;
/**
* This class is used to convert a VCalendar object to a string in the
* vCalendar (1.0) or iCalendar (vCalendar 2.0) format.
*
* @version $Id: VComponentWriter.java,v 1.2 2007-11-28 11:14:04 nichele Exp $
*/
public class VComponentWriter {
private static final String CRLF = "\r\n";
public static final int NO_FOLDING = -1;
public static final int STANDARD_FOLDING = 75;
private int maxLineWidth;
/**
* Creates a new instance of VComponentWriter, setting the max line width at
* the default value (presently, NO_FOLDING ie no line width control is
* done).
*/
public VComponentWriter() {
this.maxLineWidth = NO_FOLDING; // default value
}
/**
* Creates a new instance of VComponentWriter, setting the max line width at
* a given value.
*
* @param maxLineWidth an integer that should not be too small (some space
* is needed to write at least the property's name and
* parameters in the first line), usually
* STANDARD_FOLDING (75) or NO_FOLDING (-1, that means
* that no line width control is expected)
*/
public VComponentWriter(int maxLineWidth) {
this.maxLineWidth = maxLineWidth;
}
/**
* Converts a Parameter object into a String, following the vCalendar/
* iCalendar style.
*
* @param parameter the Parameter to be converted
* @return the result of the conversion, as a String object
*/
private String toString(Parameter parameter) {
return (parameter.name + "=" + parameter.value);
}
/**
* Converts a Property object into a String, following the vCalendar/
* iCalendar style.
*
* @param property the Property to be converted
* @return the result of the conversion, as a String object
*/
private String toString(Property property) {
StringBuffer out = new StringBuffer();
out.append(property.getName());
// Parameters
Iterator pIter = property.getParameters().iterator();
while (pIter.hasNext()) {
out.append(";");
out.append(toString((Parameter) pIter.next()));
}
out.append(":");
// Value
int column = out.length(); // column variable is now properly initialized
boolean qp = false;
String unfolded = property.getValue();
String folded;
if (maxLineWidth != NO_FOLDING &&
column + unfolded.length() > maxLineWidth) { // needs be folded
folded = "";
int truce = 0;
boolean escaped = false;
Parameter encoding = property.getParameter("ENCODING");
if (encoding != null && encoding.value != null &&
encoding.value.equalsIgnoreCase("QUOTED-PRINTABLE")) {
for (int i = 0; i < unfolded.length(); column++, i++) {
if ((truce == 0) && (column >= maxLineWidth - 2)) {
folded += "=" + CRLF; // QP soft line break
column = 0;
}
folded += unfolded.charAt(i);
if (unfolded.charAt(i) == '=') {
truce = 2; // because it could be a QP-encoded char
} else if (unfolded.charAt(i) == '\\') { // one backslash
if (!escaped) {
truce = 1; // becase it could be a \-escaped char
escaped = true;
} else { // It's the second backslash of a "\\" sequence
truce = 0;
escaped = false;
}
} else if (truce > 0) {
truce--;
}
}
} else { // non-Quoted-Printable
for (int i = 0; i < unfolded.length(); column++, i++) {
if ((truce == 0) && (column >= maxLineWidth - 1)) {
folded += CRLF + " "; // non-QP soft line break
column = 1; // because there's already a space in the
} // new line
folded += unfolded.charAt(i);
if (unfolded.charAt(i) == '\\') { // one backslash
if (!escaped) {
truce = 1; // becase it could be a \-escaped char
escaped = true;
} else { // It's the second backslash of a "\\" sequence
truce = 0;
escaped = false;
}
} else if (truce > 0) {
truce--;
}
}
}
} else { // folding's not needed
folded = unfolded;
}
out.append(folded);
out.append(CRLF);
return out.toString();
}
/**
* Converts any VComponent object into a String, following the vCalendar/
* iCalendar style.
*
* @param vComponent the VComponent to be converted
* @return the result of the conversion, as a String object
*/
public String toString(VComponent vComponent) {
StringBuffer out = open(vComponent);
Iterator pIter = vComponent.getAllProperties().iterator ();
while (pIter.hasNext()) {
Property property = (Property) pIter.next();
out.append(toString(property));
}
Iterator cIter = vComponent.getAllComponents ().iterator ();
while (cIter.hasNext()) {
VComponent subcomponent = (VComponent) cIter.next ();
out.append(toString(subcomponent));
}
return close(out, vComponent);
}
/**
* Performs the operations needed to have a StringBuffer containing the
* opening line of a VComponent converted into a vCalendar/iCalendar-style
* text string.
*
* @param vComponent the VComponent to be converted
* @return "BEGIN:" + name of the VComponent + CR + LF
*/
private StringBuffer open(VComponent vComponent) {
StringBuffer out = new StringBuffer();
out.append("BEGIN:").append(vComponent.getVComponentName()).append(CRLF);
return out;
}
/**
* Performs the operations needed to append to a given StringBuffer the
* closing line of a VComponent converted into a vCalendar/iCalendar-style
* text string.
*
* @param out the StringBuffer already filled with the VComponent's data in
* text format
* @param vComponent the VComponent to be converted
* @return out + "END:" + name of the VComponent + CR + LF
*/
private String close(StringBuffer out, VComponent vComponent) {
out.append("END:").append(vComponent.getVComponentName()).append(CRLF);
return out.toString();
}
}