Skip to content

Commit

Permalink
Quoted-printable encoding should not be used in 3.0 or 4.0 vCards
Browse files Browse the repository at this point in the history
  • Loading branch information
mangstadt committed Oct 21, 2020
1 parent 633e9c6 commit fa82fc8
Show file tree
Hide file tree
Showing 10 changed files with 249 additions and 2 deletions.
15 changes: 13 additions & 2 deletions src/main/java/ezvcard/io/json/JCardWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ protected void _write(VCard vcard, List<VCardProperty> properties) throws IOExce
String group = property.getGroup();
String name = scribe.getPropertyName().toLowerCase();
VCardParameters parameters = scribe.prepareParameters(property, targetVersion, vcard);
removeUnsupportedParameters(parameters);
VCardDataType dataType = scribe.dataType(property, targetVersion);

writer.writeProperty(group, name, parameters, dataType, value);
Expand All @@ -182,7 +183,7 @@ protected void _write(VCard vcard, List<VCardProperty> properties) throws IOExce
setCurrentValue(previousValue);
}

/**
/**
* If this object has a {@link JsonGenerator), and the generator has an
* output context, gets the current value of the output context.
*
Expand All @@ -193,7 +194,7 @@ private Object getCurrentValue() {
return (generator == null) ? null : generator.getCurrentValue();
}

/**
/**
* If this object has a {@link JsonGenerator), and the generator has an
* output context, sets the current value of the output context.
*
Expand Down Expand Up @@ -241,6 +242,16 @@ public void setPrettyPrinter(PrettyPrinter prettyPrinter) {
writer.setPrettyPrinter(prettyPrinter);
}

/**
* Removes parameters that are not supported by jCard.
* @param parameters the property parameters
*/
private void removeUnsupportedParameters(VCardParameters parameters) {
parameters.setCharset(null);
parameters.setEncoding(null);
parameters.setValue(null);
}

/**
* Flushes the jCard data stream.
* @throws IOException if there's a problem flushing the stream
Expand Down
19 changes: 19 additions & 0 deletions src/main/java/ezvcard/io/text/VCardWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import ezvcard.io.SkipMeException;
import ezvcard.io.StreamWriter;
import ezvcard.io.scribe.VCardPropertyScribe;
import ezvcard.parameter.Encoding;
import ezvcard.parameter.VCardParameters;
import ezvcard.property.Address;
import ezvcard.property.BinaryProperty;
Expand Down Expand Up @@ -328,6 +329,7 @@ protected void _write(VCard vcard, List<VCardProperty> propertiesToAdd) throws I

handleValueParameter(property, scribe, parameters);
handleLabelParameter(property, parameters);
handleQuotedPrintableEncodingParameter(property, parameters);

writer.writeProperty(property.getGroup(), scribe.getPropertyName(), new VObjectParameters(parameters.getMap()), value);

Expand Down Expand Up @@ -431,6 +433,23 @@ private void handleLabelParameter(VCardProperty property, VCardParameters parame
parameters.setLabel(label);
}

/**
* Disables quoted-printable encoding on the given property if the target
* vCard version does not support this encoding scheme.
* @param property the property
* @param parameters the property parameters
*/
private void handleQuotedPrintableEncodingParameter(VCardProperty property, VCardParameters parameters) {
if (targetVersion == VCardVersion.V2_1) {
return;
}

if (parameters.getEncoding() == Encoding.QUOTED_PRINTABLE) {
parameters.setEncoding(null);
parameters.setCharset(null);
}
}

/**
* @see TargetApplication#OUTLOOK
*/
Expand Down
1 change: 1 addition & 0 deletions src/main/java/ezvcard/io/xml/XCardDocument.java
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ private Element marshalProperty(VCardProperty property, VCard vcard) {

//marshal the parameters
VCardParameters parameters = scribe.prepareParameters(property, targetVersion, vcard);
removeUnsupportedParameters(parameters);
if (!parameters.isEmpty()) {
Element parametersElement = marshalParameters(parameters);
Node firstChild = propertyElement.getFirstChild();
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/ezvcard/io/xml/XCardWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,8 @@ private void write(VCardProperty property, VCard vcard) throws SAXException {
VCardPropertyScribe scribe = index.getPropertyScribe(property);
VCardParameters parameters = scribe.prepareParameters(property, targetVersion, vcard);

removeUnsupportedParameters(parameters);

//get the property element to write
Element propertyElement;
if (property instanceof Xml) {
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/ezvcard/io/xml/XCardWriterBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,16 @@ protected VCardVersion getTargetVersion() {
return targetVersion;
}

/**
* Removes parameters that are not supported by xCard.
* @param parameters the property parameters
*/
protected void removeUnsupportedParameters(VCardParameters parameters) {
parameters.setCharset(null);
parameters.setEncoding(null);
parameters.setValue(null);
}

/**
* Registers the data type of an experimental parameter. Experimental
* parameters use the "unknown" data type by default.
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/ezvcard/io/json/JCardWriterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import java.io.IOException;
import java.io.StringWriter;

import ezvcard.parameter.Encoding;
import ezvcard.property.FormattedName;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
Expand Down Expand Up @@ -274,6 +276,32 @@ public void write_extended_property() throws Throwable {
assertEquals(expected, sw.toString());
}

@Test
public void write_quoted_printable_encoding_not_supported() throws Exception {
StringWriter sw = new StringWriter();
JCardWriter writer = new JCardWriter(sw);
writer.setAddProdId(false);

VCard vcard = new VCard();
FormattedName fn = vcard.setFormattedName("Ömür Öde");
fn.getParameters().setEncoding(Encoding.QUOTED_PRINTABLE);
fn.getParameters().setCharset("UTF-8");
writer.write(vcard);

writer.close();

//@formatter:off
String expected =
"[\"vcard\"," +
"[" +
"[\"version\",{},\"text\",\"4.0\"]," +
"[\"fn\",{},\"text\",\"Ömür Öde\"]" +
"]" +
"]";
//@formatter:on
assertEquals(expected, sw.toString());
}

@Test
public void skipMeException() throws Throwable {
StringWriter sw = new StringWriter();
Expand Down
64 changes: 64 additions & 0 deletions src/test/java/ezvcard/io/text/VCardWriterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import java.io.StringWriter;
import java.nio.charset.Charset;

import ezvcard.parameter.Encoding;
import ezvcard.property.FormattedName;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
Expand Down Expand Up @@ -622,6 +624,68 @@ public void setTargetApplication_outlook() throws Throwable {
}
}

@Test
public void quoted_printable_encoding() throws Throwable {
VCard vcard = new VCard();
FormattedName fn = vcard.setFormattedName("Ömür Öde");
fn.getParameters().setEncoding(Encoding.QUOTED_PRINTABLE);
fn.getParameters().setCharset("UTF-8");

VCardVersion version = VCardVersion.V2_1;
{
StringWriter sw = new StringWriter();
VCardWriter writer = new VCardWriter(sw, version);
writer.setAddProdId(false);
writer.write(vcard);
writer.close();
String actual = sw.toString();

String expected = //@formatter:off
"BEGIN:VCARD\r\n" +
"VERSION:2.1\r\n" +
"FN;ENCODING=QUOTED-PRINTABLE;CHARSET=UTF-8:=C3=96m=C3=BCr =C3=96de\r\n" +
"END:VCARD\r\n"; //@formatter:on

assertEquals(expected, actual);
}

version = VCardVersion.V3_0;
{
StringWriter sw = new StringWriter();
VCardWriter writer = new VCardWriter(sw, version);
writer.setAddProdId(false);
writer.write(vcard);
writer.close();
String actual = sw.toString();

String expected = //@formatter:off
"BEGIN:VCARD\r\n" +
"VERSION:3.0\r\n" +
"FN:Ömür Öde\r\n" +
"END:VCARD\r\n"; //@formatter:on

assertEquals(expected, actual);
}

version = VCardVersion.V4_0;
{
StringWriter sw = new StringWriter();
VCardWriter writer = new VCardWriter(sw, version);
writer.setAddProdId(false);
writer.write(vcard);
writer.close();
String actual = sw.toString();

String expected = //@formatter:off
"BEGIN:VCARD\r\n" +
"VERSION:4.0\r\n" +
"FN:Ömür Öde\r\n" +
"END:VCARD\r\n"; //@formatter:on

assertEquals(expected, actual);
}
}

@Test
public void rfc6350_example() throws Throwable {
VCard vcard = new VCard();
Expand Down
26 changes: 26 additions & 0 deletions src/test/java/ezvcard/io/xml/XCardDocumentTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.io.IOException;
import java.io.InputStreamReader;

import ezvcard.parameter.Encoding;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.BeforeClass;
import org.junit.Rule;
Expand Down Expand Up @@ -679,6 +680,31 @@ public void write_utf8() throws Throwable {
assertTrue(xml.matches(".*?<note><text>\u019dote</text></note>.*"));
}

@Test
public void add_quoted_printable_encoding_not_supported() throws Throwable {
VCard vcard = new VCard();
FormattedName fn = vcard.setFormattedName("Ömür Öde");
fn.getParameters().setEncoding(Encoding.QUOTED_PRINTABLE);
fn.getParameters().setCharset("UTF-8");

XCardDocument xcard = new XCardDocument();
XCardDocumentStreamWriter writer = xcard.writer();
writer.setAddProdId(false);
writer.write(vcard);

Document actual = xcard.getDocument();

String xml = //@formatter:off
"<vcards xmlns=\"" + V4_0.getXmlNamespace() + "\">" +
"<vcard>" +
"<fn><text>Ömür Öde</text></fn>" +
"</vcard>" +
"</vcards>"; //@formatter:on
Document expected = XmlUtils.toDocument(xml);

assertXMLEqual(expected, actual);
}

@Test
public void add_embedded_vcards_not_supported() throws Throwable {
VCard vcard = new VCard();
Expand Down
21 changes: 21 additions & 0 deletions src/test/java/ezvcard/io/xml/XCardWriterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.io.IOException;
import java.io.StringWriter;

import ezvcard.parameter.Encoding;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.Before;
import org.junit.BeforeClass;
Expand Down Expand Up @@ -693,6 +694,26 @@ public void write_embedded_vcards_not_supported() throws Exception {
assertOutput(expected);
}

@Test
public void write_quoted_printable_encoding_not_supported() throws Exception {
VCard vcard = new VCard();
FormattedName fn = vcard.setFormattedName("Ömür Öde");
fn.getParameters().setEncoding(Encoding.QUOTED_PRINTABLE);
fn.getParameters().setCharset("UTF-8");

writer.write(vcard);
writer.close();

String expected = //@formatter:off
"<vcards xmlns=\"" + V4_0.getXmlNamespace() + "\">" +
"<vcard>" +
"<fn><text>Ömür Öde</text></fn>" +
"</vcard>" +
"</vcards>"; //@formatter:on

assertOutput(expected);
}

@Test
public void write_rfc6351_example() throws Exception {
VCard vcard = new VCard();
Expand Down
65 changes: 65 additions & 0 deletions src/test/java/ezvcard/issue/Issue112.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ezvcard.issue;

import ezvcard.Ezvcard;
import ezvcard.VCard;
import ezvcard.VCardVersion;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

/**
* @author Michael Angstadt
* @see "https://github.com/mangstadt/ez-vcard/issues/112"
*/
public class Issue112 {
@Test
public void test() {
String vcardStr = //@formatter:off
"BEGIN:VCARD\r\n" +
"VERSION:2.1\r\n" +
"N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=C3=96=64=65;=C3=96=6D=C3=BC=72;;;\r\n" +
"FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=C3=96=6D=C3=BC=72=20=C3=96=64=65\r\n" +
"END:VCARD\r\n"; //@formatter:on

VCard vcard = Ezvcard.parse(vcardStr).first();

VCardVersion version = VCardVersion.V2_1;
{
String actual = Ezvcard.write(vcard).version(version).prodId(false).go();
String expected = //@formatter:off
"BEGIN:VCARD\r\n" +
"VERSION:2.1\r\n" +
"N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=C3=96de;=C3=96m=C3=BCr\r\n" +
"FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=C3=96m=C3=BCr =C3=96de\r\n" +
"END:VCARD\r\n"; //@formatter:on

assertEquals(expected, actual);
}

version = VCardVersion.V3_0;
{
String actual = Ezvcard.write(vcard).version(version).prodId(false).go();
String expected = //@formatter:off
"BEGIN:VCARD\r\n" +
"VERSION:3.0\r\n" +
"N:Öde;Ömür\r\n" +
"FN:Ömür Öde\r\n" +
"END:VCARD\r\n"; //@formatter:on

assertEquals(expected, actual);
}

version = VCardVersion.V4_0;
{
String actual = Ezvcard.write(vcard).version(version).prodId(false).go();
String expected = //@formatter:off
"BEGIN:VCARD\r\n" +
"VERSION:4.0\r\n" +
"N:Öde;Ömür;;;\r\n" +
"FN:Ömür Öde\r\n" +
"END:VCARD\r\n"; //@formatter:on

assertEquals(expected, actual);
}
}
}

0 comments on commit fa82fc8

Please sign in to comment.