changeset 211:94bde95d7e18

the shared library interface should now be thread safe
author Carl Byington <carl@five-ten-sg.com>
date Mon, 08 Jun 2009 11:49:39 -0700
parents 2d1111fd70cf
children 8e17efed33c1
files ChangeLog libpst.spec.in python/python-libpst.cpp regression/regression-tests.bash src/libpst.c src/libpst.h src/lspst.c src/readpst.c
diffstat 8 files changed, 125 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Jun 06 13:53:34 2009 -0700
+++ b/ChangeLog	Mon Jun 08 11:49:39 2009 -0700
@@ -9,7 +9,6 @@
     * removed contact->access_method since we don't have a mapi element for it.
     * changed pst_attach_to_mem to return pst_binary structure.
     * decode more recurrence mapi elements.
-    * change some interfaces to be thread safe.
     * readpst changes for parallel operation on multi processor machines.
     * remove readpstlog - the debug log files are now plain ascii. Add locking
       if needed so parallel jobs can produce debug logs.
@@ -17,6 +16,7 @@
       thread safe.
     * make nested mime multipart/alternative to hold the text/html parts
       so the topmost level is almost always multipart/mixed.
+    * the shared library interface should now be thread safe.
 
 LibPST 0.6.37 (2009-04-17)
 ===============================
--- a/libpst.spec.in	Sat Jun 06 13:53:34 2009 -0700
+++ b/libpst.spec.in	Mon Jun 08 11:49:39 2009 -0700
@@ -148,12 +148,13 @@
 
 
 %changelog
-* Mon Apr 20 2009 Carl Byington <carl@five-ten-sg.com> - 0.6.38-1
+* Mon Jun 08 2009 Carl Byington <carl@five-ten-sg.com> - 0.6.38-1
 - add python interface to the shared library.
 - bump soname to version 4 for many changes to the interface.
 - better decoding of recurrence data in appointments.
 - remove readpstlog since debug log files are now plain text.
 - add readpst -j option for parallel jobs for each folder.
+- make nested mime multipart/alternative to hold the text/html parts.
 
 * Fri Apr 17 2009 Carl Byington <carl@five-ten-sg.com> - 0.6.37-1
 - add pst_attach_to_mem() back into the shared library interface.
--- a/python/python-libpst.cpp	Sat Jun 06 13:53:34 2009 -0700
+++ b/python/python-libpst.cpp	Mon Jun 08 11:49:39 2009 -0700
@@ -120,7 +120,12 @@
 }
 
 string          pst::pst_rfc2426_escape(char *str) {
-    return ::pst_rfc2426_escape(str);
+    char  *result = NULL;
+    size_t resultlen = 0;
+    char  *rc = ::pst_rfc2426_escape(str, &result, &resultlen);
+    string rrc(rc);
+    if (result) free(result);
+    return rrc;
 }
 
 string          pst::pst_rfc2425_datetime_format(const FILETIME *ft) {
@@ -136,7 +141,8 @@
 }
 
 string          pst::pst_default_charset(pst_item *item) {
-    return ::pst_default_charset(item);
+    char buf[30];
+    return string(::pst_default_charset(item, sizeof(buf), buf));
 }
 
 void            pst::pst_convert_utf8_null(pst_item *item, pst_string *str) {
--- a/regression/regression-tests.bash	Sat Jun 06 13:53:34 2009 -0700
+++ b/regression/regression-tests.bash	Mon Jun 08 11:49:39 2009 -0700
@@ -61,7 +61,7 @@
 
 
 val="valgrind --leak-check=full"
-val=''
+#val=''
 
 pushd ..
 make || exit
@@ -115,7 +115,7 @@
     #dopst  16 hourig2.pst
     #dopst  17 hourig3.pst
     dopst  18 test-mac.pst
-    dopst  19 harris.pst
+    #dopst  19 harris.pst
     dopst  20 spam.pst
     dopst  21 rendgen.pst       # single email appointment
     dopst  22 rendgen2.pst      # email appointment with no termination date
--- a/src/libpst.c	Sat Jun 06 13:53:34 2009 -0700
+++ b/src/libpst.c	Mon Jun 08 11:49:39 2009 -0700
@@ -4143,9 +4143,9 @@
 }
 
 
-char* pst_rfc2426_escape(char *str) {
-    static char*  buf    = NULL;
-    static size_t buflen = 0;
+char* pst_rfc2426_escape(char* str, char **buf, size_t* buflen) {
+    //static char*  buf    = NULL;
+    //static size_t buflen = 0;
     char *ret, *a, *b;
     size_t x = 0;
     int y, z;
@@ -4162,12 +4162,12 @@
         ret = str;
     else {
         x = strlen(str) + y - z + 1; // don't forget room for the NUL
-        if (x > buflen) {
-            buf = (char*) realloc(buf, x);
-            buflen = x;
+        if (x > *buflen) {
+            *buf = (char*) realloc(*buf, x);
+            *buflen = x;
         }
         a = str;
-        b = buf;
+        b = *buf;
         while (*a != '\0') {
             switch (*a) {
             case ',' :
@@ -4190,7 +4190,7 @@
             a++;
         }
         *b = '\0'; // NUL-terminate the string (buf)
-        ret = buf;
+        ret = *buf;
     }
     DEBUG_RET();
     return ret;
@@ -4247,12 +4247,13 @@
 /** Convert a code page integer into a string suitable for iconv()
  *
  *  @param cp the code page integer used in the pst file
+ *  @param[in]  buflen  length of the output buffer
+ *  @param[out] result  pointer to output buffer, must be at least 30 bytes
  *  @return pointer to a static buffer holding the string representation of the
  *          equivalent iconv character set
  */
-static const char* codepage(int cp);
-static const char* codepage(int cp) {
-    static char buffer[20];
+static const char* codepage(int cp, int buflen, char* result);
+static const char* codepage(int cp, int buflen, char* result) {
     switch (cp) {
         case   932 : return "iso-2022-jp";
         case   936 : return "gb2313";
@@ -4283,8 +4284,8 @@
         case 65000 : return "utf-7";
         case 65001 : return "utf-8";
         default :
-            snprintf(buffer, sizeof(buffer), "windows-%d", cp);
-            return buffer;
+            snprintf(result, buflen, "windows-%d", cp);
+            return result;
     }
     return NULL;
 }
@@ -4293,12 +4294,14 @@
 /** Get the default character set for this item. This is used to find
  *  the charset for pst_string elements that are not already in utf8 encoding.
  *  @param  item   pointer to the mapi item of interest
+ *  @param[in]  buflen  length of the output buffer
+ *  @param[out] result  pointer to output buffer, must be at least 30 bytes
  *  @return default character set as a string useable by iconv()
  */
-const char*    pst_default_charset(pst_item *item) {
+const char*    pst_default_charset(pst_item *item, int buflen, char* result) {
     return (item->body_charset.str) ? item->body_charset.str :
-           (item->message_codepage) ? codepage(item->message_codepage) :
-           (item->internet_cpid)    ? codepage(item->internet_cpid) :
+           (item->message_codepage) ? codepage(item->message_codepage, buflen, result) :
+           (item->internet_cpid)    ? codepage(item->internet_cpid, buflen, result) :
            "utf-8";
 }
 
@@ -4320,12 +4323,13 @@
  *  @param str   pointer to the mapi string of interest
  */
 void pst_convert_utf8(pst_item *item, pst_string *str) {
+    char buffer[30];
     if (str->is_utf8) return;
     if (!str->str) {
         str->str = strdup("");
         return;
     }
-    const char *charset = pst_default_charset(item);
+    const char *charset = pst_default_charset(item, sizeof(buffer), buffer);
     if (!strcasecmp("utf-8", charset)) return;  // already utf8
     DEBUG_ENT("pst_convert_utf8");
     pst_vbuf *newer = pst_vballoc(2);
--- a/src/libpst.h	Sat Jun 06 13:53:34 2009 -0700
+++ b/src/libpst.h	Mon Jun 08 11:49:39 2009 -0700
@@ -1015,13 +1015,14 @@
 
 
 /** Add any necessary escape characters for rfc2426 vcard format
- * @param str pointer to input string
+ * @param[in]     str       pointer to input string
+ * @param[in,out] result    pointer to a char* pointer that may be realloc'ed if needed
+ * @param[in,out] resultlen size of the result buffer
  * @return    pointer to output string, either the input pointer if
  *            there are no characters that need escapes, or a pointer
- *            to a different buffer containing the escaped string. In
- *            either case, you don't need to free this returned pointer.
+ *            to a possibly realloc'ed result buffer.
  */
-char*           pst_rfc2426_escape(char *str);
+char*           pst_rfc2426_escape(char* str, char** result, size_t* resultlen);
 
 
 /** Convert a FILETIME into rfc2425 date/time format 1953-10-15T23:10:00Z
@@ -1035,7 +1036,7 @@
 
 
 /** Convert a FILETIME into rfc2445 date/time format 19531015T231000Z
- * @param[in]  ft time to be converted
+ * @param[in]  ft      time to be converted
  * @param[in]  buflen  length of the output buffer
  * @param[out] result  pointer to output buffer, must be at least 30 bytes
  * @return   time in rfc2445 format
@@ -1044,6 +1045,8 @@
 
 
 /** Convert the current time rfc2445 date/time format 19531015T231000Z
+ * @param[in]  buflen  length of the output buffer
+ * @param[out] result  pointer to output buffer, must be at least 30 bytes
  * @return   time in rfc2445 format
  */
 char*           pst_rfc2445_datetime_format_now(int buflen, char* result);
@@ -1051,10 +1054,12 @@
 
 /** Get the default character set for this item. This is used to find
  *  the charset for pst_string elements that are not already in utf8 encoding.
- * @param  item   pointer to the mapi item of interest
+ * @param      item    pointer to the mapi item of interest
+ * @param[in]  buflen  length of the output buffer
+ * @param[out] result  pointer to output buffer, must be at least 30 bytes
  * @return default character set as a string useable by iconv()
  */
-const char*     pst_default_charset(pst_item *item);
+const char*     pst_default_charset(pst_item *item, int buflen, char* result);
 
 
 /** Convert str to utf8 if possible; null strings are preserved.
--- a/src/lspst.c	Sat Jun 06 13:53:34 2009 -0700
+++ b/src/lspst.c	Mon Jun 08 11:49:39 2009 -0700
@@ -47,6 +47,8 @@
 {
     struct file_ll ff;
     pst_item *item = NULL;
+    char *result = NULL;
+    size_t resultlen = 0;
 
     DEBUG_ENT("process");
     memset(&ff, 0, sizeof(ff));
@@ -82,7 +84,7 @@
                     }
                     printf("Contact");
                     if (item->contact->fullname.str)
-                        printf("\t%s", pst_rfc2426_escape(item->contact->fullname.str));
+                        printf("\t%s", pst_rfc2426_escape(item->contact->fullname.str, &result, &resultlen));
                     printf("\n");
 
                 } else if (item->email && ((item->type == PST_TYPE_NOTE) || (item->type == PST_TYPE_SCHEDULE) || (item->type == PST_TYPE_REPORT))) {
@@ -105,7 +107,7 @@
                         DEBUG_INFO(("I have a journal entry, but folder isn't specified as a journal type. Processing...\n"));
                     }
                     if (item->subject.str)
-                        printf("Journal\t%s\n", pst_rfc2426_escape(item->subject.str));
+                        printf("Journal\t%s\n", pst_rfc2426_escape(item->subject.str, &result, &resultlen));
 
                 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
                     char time_buffer[30];
@@ -117,7 +119,7 @@
                     }
                     printf("Appointment");
                     if (item->subject.str)
-                        printf("\tSUMMARY: %s", pst_rfc2426_escape(item->subject.str));
+                        printf("\tSUMMARY: %s", pst_rfc2426_escape(item->subject.str, &result, &resultlen));
                     if (item->appointment->start)
                         printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start, sizeof(time_buffer), time_buffer));
                     if (item->appointment->end)
@@ -139,6 +141,7 @@
         }
     }
     close_enter_dir(&ff);
+    if (result) free(result);
     DEBUG_RET();
 }
 
--- a/src/readpst.c	Sat Jun 06 13:53:34 2009 -0700
+++ b/src/readpst.c	Mon Jun 08 11:49:39 2009 -0700
@@ -1218,7 +1218,8 @@
     char boundary[60];
     char altboundary[66];
     char *altboundaryp = NULL;
-    char body_charset[60];
+    char body_charset[30];
+    char buffer_charset[30];
     char body_report[60];
     char sender[60];
     int  sender_known = 0;
@@ -1234,7 +1235,7 @@
     headers = (item->email->header.str) ? item->email->header.str : *extra_mime_headers;
 
     // setup default body character set and report type
-    strncpy(body_charset, pst_default_charset(item), sizeof(body_charset));
+    strncpy(body_charset, pst_default_charset(item, sizeof(buffer_charset), buffer_charset), sizeof(body_charset));
     body_charset[sizeof(body_charset)-1] = '\0';
     body_report[0] = '\0';
 
@@ -1506,9 +1507,11 @@
 }
 
 
-void write_vcard(FILE* f_output, pst_item *item, pst_item_contact* contact, char comment[])
+void write_vcard(FILE* f_output, pst_item* item, pst_item_contact* contact, char comment[])
 {
-    char time_buffer[30];
+    char*  result = NULL;
+    size_t resultlen = 0;
+    char   time_buffer[30];
     // We can only call rfc escape once per printf, since the second call
     // may free the buffer returned by the first call.
     // I had tried to place those into a single printf - Carl.
@@ -1570,96 +1573,99 @@
 
     // the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile
     fprintf(f_output, "BEGIN:VCARD\n");
-    fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname.str));
+    fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname.str, &result, &resultlen));
 
     //fprintf(f_output, "N:%s;%s;%s;%s;%s\n",
-    fprintf(f_output, "N:%s;", (!contact->surname.str)             ? "" : pst_rfc2426_escape(contact->surname.str));
-    fprintf(f_output, "%s;",   (!contact->first_name.str)          ? "" : pst_rfc2426_escape(contact->first_name.str));
-    fprintf(f_output, "%s;",   (!contact->middle_name.str)         ? "" : pst_rfc2426_escape(contact->middle_name.str));
-    fprintf(f_output, "%s;",   (!contact->display_name_prefix.str) ? "" : pst_rfc2426_escape(contact->display_name_prefix.str));
-    fprintf(f_output, "%s\n",  (!contact->suffix.str)              ? "" : pst_rfc2426_escape(contact->suffix.str));
+    fprintf(f_output, "N:%s;", (!contact->surname.str)             ? "" : pst_rfc2426_escape(contact->surname.str, &result, &resultlen));
+    fprintf(f_output, "%s;",   (!contact->first_name.str)          ? "" : pst_rfc2426_escape(contact->first_name.str, &result, &resultlen));
+    fprintf(f_output, "%s;",   (!contact->middle_name.str)         ? "" : pst_rfc2426_escape(contact->middle_name.str, &result, &resultlen));
+    fprintf(f_output, "%s;",   (!contact->display_name_prefix.str) ? "" : pst_rfc2426_escape(contact->display_name_prefix.str, &result, &resultlen));
+    fprintf(f_output, "%s\n",  (!contact->suffix.str)              ? "" : pst_rfc2426_escape(contact->suffix.str, &result, &resultlen));
 
     if (contact->nickname.str)
-        fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname.str));
+        fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname.str, &result, &resultlen));
     if (contact->address1.str)
-        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1.str));
+        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1.str, &result, &resultlen));
     if (contact->address2.str)
-        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2.str));
+        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2.str, &result, &resultlen));
     if (contact->address3.str)
-        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3.str));
+        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3.str, &result, &resultlen));
     if (contact->birthday)
         fprintf(f_output, "BDAY:%s\n", pst_rfc2425_datetime_format(contact->birthday, sizeof(time_buffer), time_buffer));
 
     if (contact->home_address.str) {
         //fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n",
-        fprintf(f_output, "ADR;TYPE=home:%s;",  (!contact->home_po_box.str)      ? "" : pst_rfc2426_escape(contact->home_po_box.str));
+        fprintf(f_output, "ADR;TYPE=home:%s;",  (!contact->home_po_box.str)      ? "" : pst_rfc2426_escape(contact->home_po_box.str, &result, &resultlen));
         fprintf(f_output, "%s;",                ""); // extended Address
-        fprintf(f_output, "%s;",                (!contact->home_street.str)      ? "" : pst_rfc2426_escape(contact->home_street.str));
-        fprintf(f_output, "%s;",                (!contact->home_city.str)        ? "" : pst_rfc2426_escape(contact->home_city.str));
-        fprintf(f_output, "%s;",                (!contact->home_state.str)       ? "" : pst_rfc2426_escape(contact->home_state.str));
-        fprintf(f_output, "%s;",                (!contact->home_postal_code.str) ? "" : pst_rfc2426_escape(contact->home_postal_code.str));
-        fprintf(f_output, "%s\n",               (!contact->home_country.str)     ? "" : pst_rfc2426_escape(contact->home_country.str));
-        fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address.str));
+        fprintf(f_output, "%s;",                (!contact->home_street.str)      ? "" : pst_rfc2426_escape(contact->home_street.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->home_city.str)        ? "" : pst_rfc2426_escape(contact->home_city.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->home_state.str)       ? "" : pst_rfc2426_escape(contact->home_state.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->home_postal_code.str) ? "" : pst_rfc2426_escape(contact->home_postal_code.str, &result, &resultlen));
+        fprintf(f_output, "%s\n",               (!contact->home_country.str)     ? "" : pst_rfc2426_escape(contact->home_country.str, &result, &resultlen));
+        fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address.str, &result, &resultlen));
     }
 
     if (contact->business_address.str) {
         //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n",
-        fprintf(f_output, "ADR;TYPE=work:%s;",  (!contact->business_po_box.str)      ? "" : pst_rfc2426_escape(contact->business_po_box.str));
+        fprintf(f_output, "ADR;TYPE=work:%s;",  (!contact->business_po_box.str)      ? "" : pst_rfc2426_escape(contact->business_po_box.str, &result, &resultlen));
         fprintf(f_output, "%s;",                ""); // extended Address
-        fprintf(f_output, "%s;",                (!contact->business_street.str)      ? "" : pst_rfc2426_escape(contact->business_street.str));
-        fprintf(f_output, "%s;",                (!contact->business_city.str)        ? "" : pst_rfc2426_escape(contact->business_city.str));
-        fprintf(f_output, "%s;",                (!contact->business_state.str)       ? "" : pst_rfc2426_escape(contact->business_state.str));
-        fprintf(f_output, "%s;",                (!contact->business_postal_code.str) ? "" : pst_rfc2426_escape(contact->business_postal_code.str));
-        fprintf(f_output, "%s\n",               (!contact->business_country.str)     ? "" : pst_rfc2426_escape(contact->business_country.str));
-        fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address.str));
+        fprintf(f_output, "%s;",                (!contact->business_street.str)      ? "" : pst_rfc2426_escape(contact->business_street.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->business_city.str)        ? "" : pst_rfc2426_escape(contact->business_city.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->business_state.str)       ? "" : pst_rfc2426_escape(contact->business_state.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->business_postal_code.str) ? "" : pst_rfc2426_escape(contact->business_postal_code.str, &result, &resultlen));
+        fprintf(f_output, "%s\n",               (!contact->business_country.str)     ? "" : pst_rfc2426_escape(contact->business_country.str, &result, &resultlen));
+        fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address.str, &result, &resultlen));
     }
 
     if (contact->other_address.str) {
         //fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n",
-        fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box.str)       ? "" : pst_rfc2426_escape(contact->other_po_box.str));
+        fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box.str)       ? "" : pst_rfc2426_escape(contact->other_po_box.str, &result, &resultlen));
         fprintf(f_output, "%s;",                ""); // extended Address
-        fprintf(f_output, "%s;",                (!contact->other_street.str)       ? "" : pst_rfc2426_escape(contact->other_street.str));
-        fprintf(f_output, "%s;",                (!contact->other_city.str)         ? "" : pst_rfc2426_escape(contact->other_city.str));
-        fprintf(f_output, "%s;",                (!contact->other_state.str)        ? "" : pst_rfc2426_escape(contact->other_state.str));
-        fprintf(f_output, "%s;",                (!contact->other_postal_code.str)  ? "" : pst_rfc2426_escape(contact->other_postal_code.str));
-        fprintf(f_output, "%s\n",               (!contact->other_country.str)      ? "" : pst_rfc2426_escape(contact->other_country.str));
-        fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address.str));
+        fprintf(f_output, "%s;",                (!contact->other_street.str)       ? "" : pst_rfc2426_escape(contact->other_street.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->other_city.str)         ? "" : pst_rfc2426_escape(contact->other_city.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->other_state.str)        ? "" : pst_rfc2426_escape(contact->other_state.str, &result, &resultlen));
+        fprintf(f_output, "%s;",                (!contact->other_postal_code.str)  ? "" : pst_rfc2426_escape(contact->other_postal_code.str, &result, &resultlen));
+        fprintf(f_output, "%s\n",               (!contact->other_country.str)      ? "" : pst_rfc2426_escape(contact->other_country.str, &result, &resultlen));
+        fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address.str, &result, &resultlen));
     }
 
-    if (contact->business_fax.str)      fprintf(f_output, "TEL;TYPE=work,fax:%s\n",         pst_rfc2426_escape(contact->business_fax.str));
-    if (contact->business_phone.str)    fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone.str));
-    if (contact->business_phone2.str)   fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone2.str));
-    if (contact->car_phone.str)         fprintf(f_output, "TEL;TYPE=car,voice:%s\n",        pst_rfc2426_escape(contact->car_phone.str));
-    if (contact->home_fax.str)          fprintf(f_output, "TEL;TYPE=home,fax:%s\n",         pst_rfc2426_escape(contact->home_fax.str));
-    if (contact->home_phone.str)        fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone.str));
-    if (contact->home_phone2.str)       fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone2.str));
-    if (contact->isdn_phone.str)        fprintf(f_output, "TEL;TYPE=isdn:%s\n",             pst_rfc2426_escape(contact->isdn_phone.str));
-    if (contact->mobile_phone.str)      fprintf(f_output, "TEL;TYPE=cell,voice:%s\n",       pst_rfc2426_escape(contact->mobile_phone.str));
-    if (contact->other_phone.str)       fprintf(f_output, "TEL;TYPE=msg:%s\n",              pst_rfc2426_escape(contact->other_phone.str));
-    if (contact->pager_phone.str)       fprintf(f_output, "TEL;TYPE=pager:%s\n",            pst_rfc2426_escape(contact->pager_phone.str));
-    if (contact->primary_fax.str)       fprintf(f_output, "TEL;TYPE=fax,pref:%s\n",         pst_rfc2426_escape(contact->primary_fax.str));
-    if (contact->primary_phone.str)     fprintf(f_output, "TEL;TYPE=phone,pref:%s\n",       pst_rfc2426_escape(contact->primary_phone.str));
-    if (contact->radio_phone.str)       fprintf(f_output, "TEL;TYPE=pcs:%s\n",              pst_rfc2426_escape(contact->radio_phone.str));
-    if (contact->telex.str)             fprintf(f_output, "TEL;TYPE=bbs:%s\n",              pst_rfc2426_escape(contact->telex.str));
-    if (contact->job_title.str)         fprintf(f_output, "TITLE:%s\n",                     pst_rfc2426_escape(contact->job_title.str));
-    if (contact->profession.str)        fprintf(f_output, "ROLE:%s\n",                      pst_rfc2426_escape(contact->profession.str));
+    if (contact->business_fax.str)      fprintf(f_output, "TEL;TYPE=work,fax:%s\n",         pst_rfc2426_escape(contact->business_fax.str, &result, &resultlen));
+    if (contact->business_phone.str)    fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone.str, &result, &resultlen));
+    if (contact->business_phone2.str)   fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone2.str, &result, &resultlen));
+    if (contact->car_phone.str)         fprintf(f_output, "TEL;TYPE=car,voice:%s\n",        pst_rfc2426_escape(contact->car_phone.str, &result, &resultlen));
+    if (contact->home_fax.str)          fprintf(f_output, "TEL;TYPE=home,fax:%s\n",         pst_rfc2426_escape(contact->home_fax.str, &result, &resultlen));
+    if (contact->home_phone.str)        fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone.str, &result, &resultlen));
+    if (contact->home_phone2.str)       fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone2.str, &result, &resultlen));
+    if (contact->isdn_phone.str)        fprintf(f_output, "TEL;TYPE=isdn:%s\n",             pst_rfc2426_escape(contact->isdn_phone.str, &result, &resultlen));
+    if (contact->mobile_phone.str)      fprintf(f_output, "TEL;TYPE=cell,voice:%s\n",       pst_rfc2426_escape(contact->mobile_phone.str, &result, &resultlen));
+    if (contact->other_phone.str)       fprintf(f_output, "TEL;TYPE=msg:%s\n",              pst_rfc2426_escape(contact->other_phone.str, &result, &resultlen));
+    if (contact->pager_phone.str)       fprintf(f_output, "TEL;TYPE=pager:%s\n",            pst_rfc2426_escape(contact->pager_phone.str, &result, &resultlen));
+    if (contact->primary_fax.str)       fprintf(f_output, "TEL;TYPE=fax,pref:%s\n",         pst_rfc2426_escape(contact->primary_fax.str, &result, &resultlen));
+    if (contact->primary_phone.str)     fprintf(f_output, "TEL;TYPE=phone,pref:%s\n",       pst_rfc2426_escape(contact->primary_phone.str, &result, &resultlen));
+    if (contact->radio_phone.str)       fprintf(f_output, "TEL;TYPE=pcs:%s\n",              pst_rfc2426_escape(contact->radio_phone.str, &result, &resultlen));
+    if (contact->telex.str)             fprintf(f_output, "TEL;TYPE=bbs:%s\n",              pst_rfc2426_escape(contact->telex.str, &result, &resultlen));
+    if (contact->job_title.str)         fprintf(f_output, "TITLE:%s\n",                     pst_rfc2426_escape(contact->job_title.str, &result, &resultlen));
+    if (contact->profession.str)        fprintf(f_output, "ROLE:%s\n",                      pst_rfc2426_escape(contact->profession.str, &result, &resultlen));
     if (contact->assistant_name.str || contact->assistant_phone.str) {
         fprintf(f_output, "AGENT:BEGIN:VCARD\n");
-        if (contact->assistant_name.str)    fprintf(f_output, "FN:%s\n",                    pst_rfc2426_escape(contact->assistant_name.str));
-        if (contact->assistant_phone.str)   fprintf(f_output, "TEL:%s\n",                   pst_rfc2426_escape(contact->assistant_phone.str));
+        if (contact->assistant_name.str)    fprintf(f_output, "FN:%s\n",                    pst_rfc2426_escape(contact->assistant_name.str, &result, &resultlen));
+        if (contact->assistant_phone.str)   fprintf(f_output, "TEL:%s\n",                   pst_rfc2426_escape(contact->assistant_phone.str, &result, &resultlen));
     }
-    if (contact->company_name.str)      fprintf(f_output, "ORG:%s\n",                       pst_rfc2426_escape(contact->company_name.str));
-    if (comment)                        fprintf(f_output, "NOTE:%s\n",                      pst_rfc2426_escape(comment));
+    if (contact->company_name.str)      fprintf(f_output, "ORG:%s\n",                       pst_rfc2426_escape(contact->company_name.str, &result, &resultlen));
+    if (comment)                        fprintf(f_output, "NOTE:%s\n",                      pst_rfc2426_escape(comment, &result, &resultlen));
 
     fprintf(f_output, "VERSION: 3.0\n");
     fprintf(f_output, "END:VCARD\n\n");
+    if (result) free(result);
     DEBUG_RET();
 }
 
 
 void write_journal(FILE* f_output, pst_item* item)
 {
-    char time_buffer[30];
+    char*  result = NULL;
+    size_t resultlen = 0;
+    char   time_buffer[30];
     pst_item_journal* journal = item->journal;
 
     // make everything utf8
@@ -1673,18 +1679,21 @@
     if (item->modify_date)
         fprintf(f_output, "LAST-MOD:%s\n",                pst_rfc2445_datetime_format(item->modify_date, sizeof(time_buffer), time_buffer));
     if (item->subject.str)
-        fprintf(f_output, "SUMMARY:%s\n",                 pst_rfc2426_escape(item->subject.str));
+        fprintf(f_output, "SUMMARY:%s\n",                 pst_rfc2426_escape(item->subject.str, &result, &resultlen));
     if (item->body.str)
-        fprintf(f_output, "DESCRIPTION:%s\n",             pst_rfc2426_escape(item->body.str));
+        fprintf(f_output, "DESCRIPTION:%s\n",             pst_rfc2426_escape(item->body.str, &result, &resultlen));
     if (journal && journal->start)
         fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(journal->start, sizeof(time_buffer), time_buffer));
     fprintf(f_output, "END:VJOURNAL\n");
+    if (result) free(result);
 }
 
 
 void write_appointment(FILE* f_output, pst_item* item, int event_open)
 {
-    char time_buffer[30];
+    char*  result = NULL;
+    size_t resultlen = 0;
+    char   time_buffer[30];
     pst_item_appointment* appointment = item->appointment;
 
     // make everything utf8
@@ -1699,15 +1708,15 @@
     if (item->modify_date)
         fprintf(f_output, "LAST-MOD:%s\n",                pst_rfc2445_datetime_format(item->modify_date, sizeof(time_buffer), time_buffer));
     if (item->subject.str)
-        fprintf(f_output, "SUMMARY:%s\n",                 pst_rfc2426_escape(item->subject.str));
+        fprintf(f_output, "SUMMARY:%s\n",                 pst_rfc2426_escape(item->subject.str, &result, &resultlen));
     if (item->body.str)
-        fprintf(f_output, "DESCRIPTION:%s\n",             pst_rfc2426_escape(item->body.str));
+        fprintf(f_output, "DESCRIPTION:%s\n",             pst_rfc2426_escape(item->body.str, &result, &resultlen));
     if (appointment && appointment->start)
         fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(appointment->start, sizeof(time_buffer), time_buffer));
     if (appointment && appointment->end)
         fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n",   pst_rfc2445_datetime_format(appointment->end, sizeof(time_buffer), time_buffer));
     if (appointment && appointment->location.str)
-        fprintf(f_output, "LOCATION:%s\n",                pst_rfc2426_escape(appointment->location.str));
+        fprintf(f_output, "LOCATION:%s\n",                pst_rfc2426_escape(appointment->location.str, &result, &resultlen));
     if (appointment) {
         switch (appointment->showas) {
             case PST_FREEBUSY_TENTATIVE:
@@ -1788,6 +1797,7 @@
         }
     }
     fprintf(f_output, "END:VEVENT\n");
+    if (result) free(result);
 }