Index: src/test/regression.c =================================================================== --- src/test/regression.c (revision 989) +++ src/test/regression.c (working copy) @@ -1268,7 +1268,7 @@ printf("%s\n",icalproperty_as_ical_string(prop)); is("test encoding of 'Timezone\\nwith a newline'", - icalproperty_as_ical_string(prop), "DTSTART;VALUE=DATE,TZID=Timezone\\nwith a newline:20090126"); + icalproperty_as_ical_string(prop), "DTSTART;VALUE=DATE,TZID=Timezone with a newline:20090126\n"); icalproperty_free(prop); } Index: src/libical/icalparameter.c =================================================================== --- src/libical/icalparameter.c (revision 989) +++ src/libical/icalparameter.c (working copy) @@ -211,15 +211,86 @@ return buf; } +/** + * checks whether this character is allowed in a (Q)SAFE-CHAR + * + * QSAFE-CHAR = WSP / %x21 / %x23-7E / NON-US-ASCII + * ; any character except CTLs and DQUOTE + * SAFE-CHAR = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E / NON-US-ASCII + * ; any character except CTLs, DQUOTE. ";", ":", "," + * WSP = SPACE / HTAB + * NON-US-ASCII = %x80-F8 + * ; Use restricted by charset parameter + * ; on outer MIME object (UTF-8 preferred) + */ +int +icalparameter_is_safe_char(char character, int quoted) +{ + if (character == ' ' || character == '\t' || character == '!' + || (character >= 0x80 && character <= 0xF8)) + { + return 1; + } + if (quoted && character >= 0x23 && character <= 0x7e) + { + return 1; + } + else if (!quoted && ((character >= 0x23 && character <= 0x2b) + || (character >= 0x2d && character <= 0x39) + || (character >= 0x3c && character <= 0x7e))) + { + return 1; + } + + return 0; +} + /** + * Appends the parameter text to the buffer, filtering out some characters not + * permitted by the specification + * + * paramtext = *SAFE-CHAR + * quoted-string= DQUOTE *QSAFE-CHAR DQUOTE + */ +void +icalparameter_append_paramtext(char** buf, char** buf_ptr, size_t* buf_size, const char* param_string) +{ + int qm = 0; + char* buf_filter = *buf_ptr; + + /* Encapsulate the property in quotes if necessary */ + if (strpbrk(param_string, ";:,") != 0) { + icalmemory_append_char (buf, buf_ptr, buf_size, '"'); + qm = 1; + } + + /* First copy the parameter value */ + icalmemory_append_string(buf, buf_ptr, buf_size, param_string); + + /* Then filter the copied data */ + while (buf_filter < *buf_ptr) + { + if (! icalparameter_is_safe_char(*buf_filter, qm)) + { + *buf_filter = ' '; + } + buf_filter++; + } + + if (qm == 1) { + icalmemory_append_char (buf, buf_ptr, buf_size, '"'); + } +} + +/** * Return a string representation of the parameter according to RFC2445. * * param = param-name "=" param-value * param-name = iana-token / x-token * param-value = paramtext /quoted-string - * paramtext = *SAFE-SHARE - * quoted-string= DQUOTE *QSAFE-CHARE DQUOTE + * paramtext = *SAFE-CHAR + * quoted-string= DQUOTE *QSAFE-CHAR DQUOTE * QSAFE-CHAR = any character except CTLs and DQUOTE * SAFE-CHAR = any character except CTLs, DQUOTE. ";", ":", "," */ @@ -268,17 +339,7 @@ icalmemory_append_string(&buf, &buf_ptr, &buf_size, "="); if(param->string !=0){ - int qm = 0; - - /* Encapsulate the property in quotes if necessary */ - if (strpbrk(param->string, ";:,") != 0) { - icalmemory_append_char (&buf, &buf_ptr, &buf_size, '"'); - qm = 1; - } - icalmemory_append_string(&buf, &buf_ptr, &buf_size, param->string); - if (qm == 1) { - icalmemory_append_char (&buf, &buf_ptr, &buf_size, '"'); - } + icalparameter_append_paramtext(&buf, &buf_ptr, &buf_size, param->string); } else if (param->data != 0){ const char* str = icalparameter_enum_to_string(param->data); icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);