summaryrefslogtreecommitdiff
path: root/library/backend/vobject.cpp
Side-by-side diff
Diffstat (limited to 'library/backend/vobject.cpp') (more/less context) (show whitespace changes)
-rw-r--r--library/backend/vobject.cpp104
1 files changed, 100 insertions, 4 deletions
diff --git a/library/backend/vobject.cpp b/library/backend/vobject.cpp
index 9c2ba3b..e6f6b78 100644
--- a/library/backend/vobject.cpp
+++ b/library/backend/vobject.cpp
@@ -984,102 +984,181 @@ static int writeBase64(OFile *fp, unsigned char *s, long len)
}
// fill in 'quad' with the appropriate four characters
for (i = 3; i >= 0; i--) {
b = (unsigned char)(trip & 0x3F);
trip = trip >> 6;
if ((3 - i) < (cur - len))
quad[i] = '='; // pad char
else if (b < 26) quad[i] = (char)b + 'A';
else if (b < 52) quad[i] = (char)(b - 26) + 'a';
else if (b < 62) quad[i] = (char)(b - 52) + '0';
else if (b == 62) quad[i] = '+';
else quad[i] = '/';
}
// now output 'quad' with appropriate whitespace and line ending
appendsOFile(fp, (numQuads == 0 ? " " : ""));
appendsOFile(fp, quad);
appendsOFile(fp, ((cur >= len)?"\n" :(numQuads==MAXQUADS-1?"\n" : "")));
numQuads = (numQuads + 1) % MAXQUADS;
}
appendcOFile(fp,'\n');
return 1;
}
+static const char *replaceChar(unsigned char c)
+{
+ if (c == '\n') {
+ return "=0A=\n";
+ } else if (
+ (c >= 'A' && c <= 'Z')
+ ||
+ (c >= 'a' && c <= 'z')
+ ||
+ (c >= '0' && c <= '9')
+ ||
+ (c >= '\'' && c <= ')')
+ ||
+ (c >= '+' && c <= '-')
+ ||
+ (c == '/')
+ ||
+ (c == '?')
+ ||
+ (c == ' '))
+ {
+ return 0;
+ }
+
+ static char trans[4];
+ trans[0] = '=';
+ trans[3] = '\0';
+ int rem = c % 16;
+ int div = c / 16;
+
+ if (div < 10)
+ trans[1] = '0' + div;
+ else
+ trans[1] = 'A' + (div - 10);
+
+ if (rem < 10)
+ trans[2] = '0' + rem;
+ else
+ trans[2] = 'A' + (rem - 10);
+
+ return trans;
+}
+
static void writeQPString(OFile *fp, const char *s)
{
+ /*
+ only A-Z, 0-9 and
+ "'" (ASCII code 39)
+ "(" (ASCII code 40)
+ ")" (ASCII code 41)
+ "+" (ASCII code 43)
+ "," (ASCII code 44)
+ "-" (ASCII code 45)
+ "/" (ASCII code 47)
+ "?" (ASCII code 63)
+
+ should remain un-encoded.
+ '=' needs to be encoded as it is the escape character.
+ ';' needs to be as it is a field separator.
+
+ */
const char *p = s;
while (*p) {
- if (*p == '\n') {
- if (p[1]) appendsOFile(fp,"=0A=");
- }
+ const char *rep = replaceChar(*p);
+ if (rep)
+ appendsOFile(fp, rep);
+ else
appendcOFile(fp,*p);
p++;
}
}
-
+static bool includesUnprintable(VObject *o)
+{
+ if (o) {
+ if (VALUE_TYPE(o) == VCVT_STRINGZ) {
+ const char *p = STRINGZ_VALUE_OF(o);
+ if (p) {
+ while (*p) {
+ if (replaceChar(*p))
+ return TRUE;
+ p++;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
static void writeVObject_(OFile *fp, VObject *o);
static void writeValue(OFile *fp, VObject *o, unsigned long size)
{
if (o == 0) return;
switch (VALUE_TYPE(o)) {
case VCVT_STRINGZ: {
writeQPString(fp, STRINGZ_VALUE_OF(o));
break;
}
case VCVT_UINT: {
char buf[16];
sprintf(buf,"%u", INTEGER_VALUE_OF(o));
appendsOFile(fp,buf);
break;
}
case VCVT_ULONG: {
char buf[16];
sprintf(buf,"%lu", LONG_VALUE_OF(o));
appendsOFile(fp,buf);
break;
}
case VCVT_RAW: {
appendcOFile(fp,'\n');
writeBase64(fp,(unsigned char*)(ANY_VALUE_OF(o)),size);
break;
}
case VCVT_VOBJECT:
appendcOFile(fp,'\n');
writeVObject_(fp,VOBJECT_VALUE_OF(o));
break;
}
}
static void writeAttrValue(OFile *fp, VObject *o)
{
if (NAME_OF(o)) {
struct PreDefProp *pi;
pi = lookupPropInfo(NAME_OF(o));
if (pi && ((pi->flags & PD_INTERNAL) != 0)) return;
+ if ( includesUnprintable(o) ) {
+ appendsOFile(fp, ";" VCEncodingProp "=" VCQuotedPrintableProp);
+ appendsOFile(fp, ";" VCCharSetProp "=" "UTF-8");
+ }
appendcOFile(fp,';');
appendsOFile(fp,NAME_OF(o));
}
else
appendcOFile(fp,';');
if (VALUE_TYPE(o)) {
appendcOFile(fp,'=');
writeValue(fp,o,0);
}
}
static void writeGroup(OFile *fp, VObject *o)
{
char buf1[256];
char buf2[256];
strcpy(buf1,NAME_OF(o));
while ((o=isAPropertyOf(o,VCGroupingProp)) != 0) {
strcpy(buf2,STRINGZ_VALUE_OF(o));
strcat(buf2,".");
strcat(buf2,buf1);
strcpy(buf1,buf2);
}
appendsOFile(fp,buf1);
}
@@ -1101,65 +1180,82 @@ static void writeProp(OFile *fp, VObject *o)
VObjectIterator t;
const char **fields_ = 0;
pi = lookupPropInfo(NAME_OF(o));
if (pi && ((pi->flags & PD_BEGIN) != 0)) {
writeVObject_(fp,o);
return;
}
if (isAPropertyOf(o,VCGroupingProp))
writeGroup(fp,o);
else
appendsOFile(fp,NAME_OF(o));
if (pi) fields_ = pi->fields;
initPropIterator(&t,o);
while (moreIteration(&t)) {
const char *s;
VObject *eachProp = nextVObject(&t);
s = NAME_OF(eachProp);
if (qstricmp(VCGroupingProp,s) && !inList(fields_,s))
writeAttrValue(fp,eachProp);
}
if (fields_) {
int i = 0, n = 0;
const char** fields = fields_;
/* output prop as fields */
+ bool printable = TRUE;
+ while (*fields && printable) {
+ VObject *t = isAPropertyOf(o,*fields);
+ if (includesUnprintable(t))
+ printable = FALSE;
+ fields++;
+ }
+ fields = fields_;
+ if (!printable) {
+ appendsOFile(fp, ";" VCEncodingProp "=" VCQuotedPrintableProp);
+ appendsOFile(fp, ";" VCCharSetProp "=" "UTF-8");
+ }
appendcOFile(fp,':');
while (*fields) {
VObject *t = isAPropertyOf(o,*fields);
i++;
if (t) n = i;
fields++;
}
fields = fields_;
for (i=0;i<n;i++) {
writeValue(fp,isAPropertyOf(o,*fields),0);
fields++;
if (i<(n-1)) appendcOFile(fp,';');
}
}
}
+
if (VALUE_TYPE(o)) {
+ if ( includesUnprintable(o) ) {
+ appendsOFile(fp, ";" VCEncodingProp "=" VCQuotedPrintableProp);
+ appendsOFile(fp, ";" VCCharSetProp "=" "UTF-8");
+ }
unsigned long size = 0;
VObject *p = isAPropertyOf(o,VCDataSizeProp);
if (p) size = LONG_VALUE_OF(p);
appendcOFile(fp,':');
writeValue(fp,o,size);
}
appendcOFile(fp,'\n');
}
static void writeVObject_(OFile *fp, VObject *o)
{
if (NAME_OF(o)) {
struct PreDefProp *pi;
pi = lookupPropInfo(NAME_OF(o));
if (pi && ((pi->flags & PD_BEGIN) != 0)) {
VObjectIterator t;
const char *begin = NAME_OF(o);
appendsOFile(fp,"BEGIN:");
appendsOFile(fp,begin);
appendcOFile(fp,'\n');
initPropIterator(&t,o);
while (moreIteration(&t)) {