# HG changeset patch # User Carl Byington # Date 1242241195 25200 # Node ID e3a46f66332bb7527091c158c4427d61e5263b07 # Parent 7c60d6d1c68161480687f6e3caf2129e43b99488 more changes in recurrence decoding diff -r 7c60d6d1c681 -r e3a46f66332b configure.in --- a/configure.in Tue May 12 19:34:49 2009 -0700 +++ b/configure.in Wed May 13 11:59:55 2009 -0700 @@ -272,7 +272,7 @@ esac ], [ - enable_python=no + enable_python=yes ]) AC_MSG_RESULT([$enable_python]) AM_CONDITIONAL(PYTHON_INTERFACE, [test "$enable_python" = "yes"]) diff -r 7c60d6d1c681 -r e3a46f66332b libpst.spec.in --- a/libpst.spec.in Tue May 12 19:34:49 2009 -0700 +++ b/libpst.spec.in Wed May 13 11:59:55 2009 -0700 @@ -83,7 +83,7 @@ %build -%configure --enable-libpst-shared --enable-python +%configure --enable-libpst-shared make %{?_smp_mflags} @@ -150,7 +150,8 @@ %changelog * Mon Apr 20 2009 Carl Byington - 0.6.38-1 - add python interface to the shared library. -- bump soname to version 4. +- bump soname to version 4 for many changes to the interface. +- better decoding of recurrence data in appointments. * Fri Apr 17 2009 Carl Byington - 0.6.37-1 - add pst_attach_to_mem() back into the shared library interface. diff -r 7c60d6d1c681 -r e3a46f66332b python/python-libpst.cpp --- a/python/python-libpst.cpp Tue May 12 19:34:49 2009 -0700 +++ b/python/python-libpst.cpp Wed May 13 11:59:55 2009 -0700 @@ -134,11 +134,15 @@ } string pst::pst_rfc2425_datetime_format(const FILETIME *ft) { - return ::pst_rfc2425_datetime_format((FILETIME *)ft); // cast away const is ok, since libpst did not modify it anyway, and the signature will change in more recent versions + char buf[30]; + ::pst_rfc2425_datetime_format(ft, sizeof(buf), buf); + return string(buf); } string pst::pst_rfc2445_datetime_format(const FILETIME *ft) { - return ::pst_rfc2445_datetime_format((FILETIME *)ft); // cast away const is ok, since libpst did not modify it anyway, and the signature will change in more recent versions + char buf[30]; + ::pst_rfc2445_datetime_format(ft, sizeof(buf), buf); + return string(buf); } string pst::pst_default_charset(pst_item *item) { @@ -203,13 +207,6 @@ } }; -struct make_python_pst_recurrence { - static PyObject* convert(pst_recurrence* const &s) { - if (s) return to_python_indirect()(s); - return NULL; - } -}; - struct make_python_pst_item_email { static PyObject* convert(pst_item_email* const &s) { if (s) return to_python_indirect()(s); @@ -252,7 +249,6 @@ to_python_converter(); to_python_converter(); to_python_converter(); - to_python_converter(); to_python_converter(); to_python_converter(); to_python_converter(); @@ -528,6 +524,10 @@ .def_readonly("parm5", &pst_recurrence::parm5) .def_readonly("termination", &pst_recurrence::termination) .def_readonly("interval", &pst_recurrence::interval) + .def_readonly("bydaymask", &pst_recurrence::bydaymask) + .def_readonly("dayofmonth", &pst_recurrence::dayofmonth) + .def_readonly("monthofyear", &pst_recurrence::monthofyear) + .def_readonly("position", &pst_recurrence::position) .def_readonly("count", &pst_recurrence::count) ; diff -r 7c60d6d1c681 -r e3a46f66332b regression/regression-tests.bash --- a/regression/regression-tests.bash Tue May 12 19:34:49 2009 -0700 +++ b/regression/regression-tests.bash Wed May 13 11:59:55 2009 -0700 @@ -121,9 +121,10 @@ #dopst 18 test-mac.pst ##dopst 19 harris.pst #dopst 20 spam.pst - dopst 21 rendgen.pst # single email appointment + #dopst 21 rendgen.pst # single email appointment dopst 22 rendgen2.pst # email appointment with no termination date - dopst 23 rendgen3.pst # mime signed email + #dopst 23 rendgen3.pst # mime signed email + dopst 24 rendgen4.pst # appointment test cases fi grep 'lost:' *err | grep -v 'lost: 0 ' diff -r 7c60d6d1c681 -r e3a46f66332b src/libpst.c --- a/src/libpst.c Tue May 12 19:34:49 2009 -0700 +++ b/src/libpst.c Wed May 13 11:59:55 2009 -0700 @@ -2014,14 +2014,14 @@ // malloc space and copy the item filetime #define LIST_COPY_TIME(label, targ) { \ if (list->elements[x]->type != 0x40) { \ - DEBUG_WARN(("src not 0x40 for filetime dst\n")); \ + DEBUG_WARN(("src not 0x40 for filetime dst\n")); \ DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size); \ } \ targ = (FILETIME*) realloc(targ, sizeof(FILETIME)); \ memcpy(targ, list->elements[x]->data, list->elements[x]->size); \ LE32_CPU(targ->dwLowDateTime); \ LE32_CPU(targ->dwHighDateTime); \ - DEBUG_EMAIL((label" - %s", pst_fileTimeToAscii(targ))); \ + DEBUG_EMAIL((label" - %s", pst_fileTimeToAscii(targ, time_buffer))); \ } #define LIST_COPY_EMAIL_TIME(label, targ) { \ @@ -2096,6 +2096,7 @@ while (list) { int32_t x; + char time_buffer[30]; for (x=0; xcount_elements; x++) { int32_t t; DEBUG_EMAIL(("#%d - mapi-id: %#x type: %#x length: %#x\n", x, list->elements[x]->mapi_id, list->elements[x]->type, list->elements[x]->size)); @@ -2961,10 +2962,10 @@ LIST_COPY_APPT_BOOL("Reminder alarm", item->appointment->alarm); break; case 0x8516: // Common start - DEBUG_EMAIL(("Common Start Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data))); + DEBUG_EMAIL(("Common Start Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer))); break; case 0x8517: // Common end - DEBUG_EMAIL(("Common End Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data))); + DEBUG_EMAIL(("Common End Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer))); break; case 0x851f: // Play reminder sound filename LIST_COPY_APPT_STR("Appointment reminder sound filename", item->appointment->alarm_filename); @@ -3055,7 +3056,7 @@ } else if (list->elements[x]->type == (uint32_t)0x0040) { DEBUG_WARN(("Unknown type %#x Date = \"%s\"\n", list->elements[x]->mapi_id, - pst_fileTimeToAscii((FILETIME*)list->elements[x]->data))); + pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer))); } else if (list->elements[x]->type == (uint32_t)0x0048) { DEBUG_WARN(("Unknown type %#x OLE GUID [size = %#x]\n", list->elements[x]->mapi_id, @@ -4107,7 +4108,7 @@ } -char *pst_rfc2426_escape(char *str) { +char* pst_rfc2426_escape(char *str) { static char* buf = NULL; static size_t buflen = 0; char *ret, *a, *b; @@ -4171,43 +4172,40 @@ } -char *pst_rfc2425_datetime_format(const FILETIME *ft) { - static char buffer[30]; - struct tm* stm = NULL; +char* pst_rfc2425_datetime_format(const FILETIME* ft, int buflen, char* result) { + struct tm stm; DEBUG_ENT("rfc2425_datetime_format"); - stm = pst_fileTimeToStructTM(ft); - if (strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", stm)==0) { + pst_fileTimeToStructTM(ft, &stm); + if (strftime(result, buflen, "%Y-%m-%dT%H:%M:%SZ", &stm)==0) { DEBUG_INFO(("Problem occured formatting date\n")); } DEBUG_RET(); - return buffer; + return result; } -char *pst_rfc2445_datetime_format(const FILETIME *ft) { - static char buffer[30]; - struct tm* stm = NULL; +char* pst_rfc2445_datetime_format(const FILETIME* ft, int buflen, char* result) { + struct tm stm; DEBUG_ENT("rfc2445_datetime_format"); - stm = pst_fileTimeToStructTM(ft); - if (strftime(buffer, sizeof(buffer), "%Y%m%dT%H%M%SZ", stm)==0) { + pst_fileTimeToStructTM(ft, &stm); + if (strftime(result, buflen, "%Y%m%dT%H%M%SZ", &stm)==0) { DEBUG_INFO(("Problem occured formatting date\n")); } DEBUG_RET(); - return buffer; + return result; } -char *pst_rfc2445_datetime_format_now() { - static char buffer[30]; +char* pst_rfc2445_datetime_format_now(int buflen, char* result) { struct tm stm; time_t t = time(NULL); DEBUG_ENT("rfc2445_datetime_format_now"); gmtime_r(&t, &stm); - if (strftime(buffer, sizeof(buffer), "%Y%m%dT%H%M%SZ", &stm)==0) { + if (strftime(result, buflen, "%Y%m%dT%H%M%SZ", &stm)==0) { DEBUG_INFO(("Problem occured formatting date\n")); } DEBUG_RET(); - return buffer; + return result; } @@ -4317,6 +4315,7 @@ */ pst_recurrence* pst_convert_recurrence(pst_item_appointment* appt) { + const int bias = 30 * 24 * 60; // minutes in 30 days int m[4] = {3,4,4,5}; pst_recurrence *r = pst_malloc(sizeof(pst_recurrence)); memset(r, 0, sizeof(pst_recurrence)); @@ -4328,7 +4327,7 @@ if (i <= s) { r->type = PST_LE_GET_UINT8(p+i) - 0x0a; i += 2; } if (i+4 <= s) { r->sub_type = PST_LE_GET_UINT32(p+i); i += 4; } if (r->sub_type <= 3) { - int n = m[r->sub_type]; + int n = m[r->sub_type]; // number of parms for this sub_type int j = 0; for (j=0; jparm1 + j) = PST_LE_GET_UINT32(p+i); i += 4; } @@ -4338,21 +4337,44 @@ if (i+4 <= s) { r->count = PST_LE_GET_UINT32(p+i); i += 4; } switch (r->type) { case 0: // daily - r->interval = r->parm2 / (24 * 60); // was minutes between recurrences - if (r->sub_type) r->interval = 0; // !! don't handle sub-type 1 yet + if (r->sub_type == 0) { + // simple daily + r->interval = r->parm2 / (24 * 60); // was minutes between recurrences + } + else { + // daily every weekday, subset of weekly + r->interval = 1; + r->bydaymask = r->parm4; + } break; case 1: // weekly - r->interval = r->parm2; + r->interval = r->parm2; + r->bydaymask = r->parm4; break; case 2: // monthly r->interval = r->parm2; - // two flavors, every month on the Dth day, and every month on the Nth Tuesday - // those are not handled here. + if (r->sub_type == 2) { + // monthly on day d + r->dayofmonth = r->parm4; + } + else { + // monthly on 2nd tuesday + r->bydaymask = r->parm4; + r->position = r->parm5; + } break; case 3: // yearly - r->interval = 0; - // two flavors, every year on the Dth day of the Mth month, and every year on the Nth Tuesday of the Mth month - // those are not handled here. + r->interval = 1; + r->monthofyear = ((r->parm1 + bias/2) / bias) + 1; + if (r->sub_type == 2) { + // yearly on day d of month m + r->dayofmonth = r->parm4; + } + else { + // yearly on 2nd tuesday of month m + r->bydaymask = r->parm4; + r->position = r->parm5; + } break; default: break; diff -r 7c60d6d1c681 -r e3a46f66332b src/libpst.h --- a/src/libpst.h Tue May 12 19:34:49 2009 -0700 +++ b/src/libpst.h Wed May 13 11:59:55 2009 -0700 @@ -655,6 +655,14 @@ uint32_t termination; /** recurrence interval in terms of the recurrence type */ uint32_t interval; + /** bit mask of days of the week */ + uint32_t bydaymask; + /** day of month for monthly and yearly recurrences */ + uint32_t dayofmonth; + /** month of year for yearly recurrences */ + uint32_t monthofyear; + /** occurence of day for 2nd Tuesday of month, in which case position is 2 */ + uint32_t position; /** number of occurrences, even if recurrence terminates based on date */ uint32_t count; // there is more data, including the termination date, @@ -1025,28 +1033,32 @@ * to a different buffer containing the escaped string. In * either case, you don't need to free this returned pointer. */ -char * pst_rfc2426_escape(char *str); +char* pst_rfc2426_escape(char *str); /** Convert a FILETIME into rfc2425 date/time format 1953-10-15T23:10:00Z * which is the same as one of the forms in the ISO3601 standard - * @param 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 rfc2425 format */ -char * pst_rfc2425_datetime_format(const FILETIME *ft); +char* pst_rfc2425_datetime_format(const FILETIME* ft, int buflen, char* result); /** Convert a FILETIME into rfc2445 date/time format 19531015T231000Z - * @param 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 */ -char * pst_rfc2445_datetime_format(const FILETIME *ft); +char* pst_rfc2445_datetime_format(const FILETIME* ft, int buflen, char* result); /** Convert the current time rfc2445 date/time format 19531015T231000Z * @return time in rfc2445 format */ -char * pst_rfc2445_datetime_format_now(); +char* pst_rfc2445_datetime_format_now(int buflen, char* result); /** Get the default character set for this item. This is used to find diff -r 7c60d6d1c681 -r e3a46f66332b src/lspst.c --- a/src/lspst.c Tue May 12 19:34:49 2009 -0700 +++ b/src/lspst.c Wed May 13 11:59:55 2009 -0700 @@ -108,6 +108,7 @@ printf("Journal\t%s\n", pst_rfc2426_escape(item->subject.str)); } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { + char time_buffer[30]; if (!ff.type) ff.type = item->type; // Process Calendar Appointment item DEBUG_MAIN(("main: Processing Appointment Entry\n")); @@ -118,9 +119,9 @@ if (item->subject.str) printf("\tSUMMARY: %s", pst_rfc2426_escape(item->subject.str)); if (item->appointment->start) - printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start)); + printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start, sizeof(time_buffer), time_buffer)); if (item->appointment->end) - printf("\tEND: %s", pst_rfc2445_datetime_format(item->appointment->end)); + printf("\tEND: %s", pst_rfc2445_datetime_format(item->appointment->end, sizeof(time_buffer), time_buffer)); printf("\tALL DAY: %s", (item->appointment->all_day==1 ? "Yes" : "No")); printf("\n"); diff -r 7c60d6d1c681 -r e3a46f66332b src/readpst.c --- a/src/readpst.c Tue May 12 19:34:49 2009 -0700 +++ b/src/readpst.c Wed May 13 11:59:55 2009 -0700 @@ -57,8 +57,7 @@ void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers); void write_vcard(FILE* f_output, pst_item *item, pst_item_contact* contact, char comment[]); void write_journal(FILE* f_output, pst_item* item); -int file_time_compare(FILETIME* left, FILETIME* right); -void write_appointment(FILE* f_output, pst_item *item); +void write_appointment(FILE* f_output, pst_item *item, int event_open); void create_enter_dir(struct file_ll* f, pst_item *item); void close_enter_dir(struct file_ll *f); @@ -220,7 +219,7 @@ else { ff.item_count++; if (mode == MODE_SEPARATE) mk_separate_file(&ff); - write_appointment(ff.output, item); + write_appointment(ff.output, item, 0); fprintf(ff.output, "\n"); } @@ -1042,10 +1041,11 @@ { fprintf(f_output, "BEGIN:VCALENDAR\n"); fprintf(f_output, "VERSION:2.0\n"); - fprintf(f_output, "PRODID:LibPST\n"); + fprintf(f_output, "PRODID:LibPST v%s\n", VERSION); fprintf(f_output, "METHOD:%s\n", method); + fprintf(f_output, "BEGIN:VEVENT\n"); fprintf(f_output, "ORGANIZER;CN=\"%s\":MAILTO:%s\n", item->email->outlook_sender_name.str, sender); - write_appointment(f_output, item); + write_appointment(f_output, item, 1); fprintf(f_output, "END:VCALENDAR\n"); } @@ -1054,7 +1054,7 @@ { const char* method = "REQUEST"; const char* charset = "utf-8"; - char fname[20]; + char fname[30]; if (!item->appointment) return; // inline appointment request @@ -1359,6 +1359,7 @@ void write_vcard(FILE* f_output, pst_item *item, pst_item_contact* contact, char comment[]) { + 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. @@ -1438,7 +1439,7 @@ if (contact->address3.str) fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3.str)); if (contact->birthday) - fprintf(f_output, "BDAY:%s\n", pst_rfc2425_datetime_format(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", @@ -1509,6 +1510,7 @@ void write_journal(FILE* f_output, pst_item* item) { + char time_buffer[30]; pst_item_journal* journal = item->journal; // make everything utf8 @@ -1516,40 +1518,24 @@ pst_convert_utf8_null(item, &item->body); fprintf(f_output, "BEGIN:VJOURNAL\n"); - fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now()); + fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now(sizeof(time_buffer), time_buffer)); if (item->create_date) - fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date)); + fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date, sizeof(time_buffer), time_buffer)); if (item->modify_date) - fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(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)); if (item->body.str) fprintf(f_output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str)); if (journal && journal->start) - fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(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"); } -/** - compare two FILETIME objects after converting to unix time_t. This - allows FILETIMEs that are beyond the range of time_t representaion to - be converted to 0, and therefore seem to be less than the right - side. The actual recurrence end values seen in pst files are very - large (outside the range of 32 bit time_t), but still finite. That is - a strange way to represent an infinite recurrence. - */ -int file_time_compare(FILETIME* left, FILETIME* right) +void write_appointment(FILE* f_output, pst_item* item, int event_open) { - time_t delta = pst_fileTimeToUnixTime(left) - pst_fileTimeToUnixTime(right); - if (delta < 0) return -1; - if (delta > 0) return 1; - return 0; -} - - -void write_appointment(FILE* f_output, pst_item* item) -{ + char time_buffer[30]; pst_item_appointment* appointment = item->appointment; // make everything utf8 @@ -1557,20 +1543,20 @@ pst_convert_utf8_null(item, &item->body); pst_convert_utf8_null(item, &appointment->location); - fprintf(f_output, "BEGIN:VEVENT\n"); - fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now()); + if (!event_open) fprintf(f_output, "BEGIN:VEVENT\n"); + fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now(sizeof(time_buffer), time_buffer)); if (item->create_date) - fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date)); + fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date, sizeof(time_buffer), time_buffer)); if (item->modify_date) - fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(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)); if (item->body.str) fprintf(f_output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str)); if (appointment && appointment->start) - fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(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)); + 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)); if (appointment) { @@ -1588,10 +1574,29 @@ } if (appointment->is_recurring) { const char* rules[] = {"DAILY", "WEEKLY", "MONTHLY", "YEARLY"}; + const char* days[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; pst_recurrence *rdata = pst_convert_recurrence(appointment); fprintf(f_output, "RRULE:FREQ=%s", rules[rdata->type]); - if (rdata->count) fprintf(f_output, ";COUNT=%u", rdata->count); - if (rdata->interval) fprintf(f_output, ";INTERVAL=%u", rdata->interval); + if (rdata->count) fprintf(f_output, ";COUNT=%u", rdata->count); + if (rdata->interval) fprintf(f_output, ";INTERVAL=%u", rdata->interval); + if (rdata->dayofmonth) fprintf(f_output, ";BYMONTHDAY=%d", rdata->dayofmonth); + if (rdata->monthofyear) fprintf(f_output, ";BYMONTH=%d", rdata->monthofyear); + if (rdata->position) fprintf(f_output, ";BYSETPOS=%d", rdata->position); + if (rdata->bydaymask) { + char byday[40]; + int empty = 1; + int i=0; + memset(byday, 0, sizeof(byday)); + for (i=0; i<6; i++) { + int bit = 1 << i; + if (bit & rdata->bydaymask) { + char temp[40]; + snprintf(temp, sizeof(temp), "%s%s%s", byday, (empty) ? "BYDAY=" : ";", days[i]); + strcpy(byday, temp); + empty = 0; + } + } + } fprintf(f_output, "\n"); pst_free_recurrence(rdata); } diff -r 7c60d6d1c681 -r e3a46f66332b src/timeconv.c --- a/src/timeconv.c Tue May 12 19:34:49 2009 -0700 +++ b/src/timeconv.c Wed May 13 11:59:55 2009 -0700 @@ -2,17 +2,17 @@ -char * pst_fileTimeToAscii(const FILETIME* filetime) { +char* pst_fileTimeToAscii(const FILETIME* filetime, char* result) { time_t t; t = pst_fileTimeToUnixTime(filetime); - return ctime(&t); + return ctime_r(&t, result); } -struct tm * pst_fileTimeToStructTM (const FILETIME *filetime) { +void pst_fileTimeToStructTM (const FILETIME *filetime, struct tm *result) { time_t t1; t1 = pst_fileTimeToUnixTime(filetime); - return gmtime(&t1); + gmtime_r(&t1, result); } diff -r 7c60d6d1c681 -r e3a46f66332b src/timeconv.h --- a/src/timeconv.h Tue May 12 19:34:49 2009 -0700 +++ b/src/timeconv.h Wed May 13 11:59:55 2009 -0700 @@ -6,9 +6,24 @@ #ifdef __cplusplus extern "C" { #endif - char * pst_fileTimeToAscii (const FILETIME *filetime); - struct tm * pst_fileTimeToStructTM (const FILETIME *filetime); - time_t pst_fileTimeToUnixTime( const FILETIME *filetime); + /** Convert a FILETIME to ascii printable local time. + @param[in] filetime time structure to be converted + @param[out] result pointer to output buffer, must be at least 30 bytes. + @return result pointer to the output buffer + */ + char* pst_fileTimeToAscii (const FILETIME* filetime, char* result); + + /** Convert a FILETIME to unix struct tm. + @param[in] filetime time structure to be converted + @param[out] result pointer to output struct tm + */ + void pst_fileTimeToStructTM (const FILETIME* filetime, struct tm *result); + + /** Convert a FILETIME to unix time_t value. + @param[in] filetime time structure to be converted + @return result time_t value + */ + time_t pst_fileTimeToUnixTime( const FILETIME* filetime); #ifdef __cplusplus } #endif