-rw-r--r-- | library/backend/vobject.cpp | 104 |
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)) {
|