diff -up libical-2.0.0/src/libical/icalrecur.c.rscale libical-2.0.0/src/libical/icalrecur.c --- libical-2.0.0/src/libical/icalrecur.c.rscale 2016-02-11 13:27:37.626579781 +0100 +++ libical-2.0.0/src/libical/icalrecur.c 2016-02-11 14:49:56.751367100 +0100 @@ -134,6 +134,7 @@ #endif #include "icalrecur.h" +#include "icalarray.h" #include "icalerror.h" #include "icalmemory.h" #include "icaltimezone.h" @@ -186,6 +187,139 @@ #define LEAP_MONTH 0x1000 +#if defined(HAVE_PTHREAD) +#include +static pthread_mutex_t rscale_texts_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static icalarray *rscale_texts = NULL; + +static void initialize_rscale_texts(void) +{ +#if defined(HAVE_LIBICU) + UErrorCode status = U_ZERO_ERROR; + UEnumeration *en; + const char *cal; +#endif + +#if defined(HAVE_PTHREAD) + pthread_mutex_lock(&rscale_texts_mutex); +#endif + + if (rscale_texts != NULL) { + #if defined(HAVE_PTHREAD) + pthread_mutex_unlock(&rscale_texts_mutex); + #endif + return; + } + + rscale_texts = icalarray_new(sizeof(char **), 20); + +#if defined(HAVE_LIBICU) + en = ucal_getKeywordValuesForLocale("calendar", NULL, FALSE, &status); + while ((cal = uenum_next(en, NULL, &status))) { + char *copy = icalmemory_strdup(cal); + icalarray_append(rscale_texts, ©); + } + uenum_close(en); +#endif + +#if defined(HAVE_PTHREAD) + pthread_mutex_unlock(&rscale_texts_mutex); +#endif +} + +static const char *match_rscale_text(const char *text) +{ + size_t ii; + const char *res = NULL; + + if(!text) { + return NULL; + } + + initialize_rscale_texts(); + +#if defined(HAVE_PTHREAD) + pthread_mutex_lock(&rscale_texts_mutex); +#endif + + for(ii = 0; rscale_texts && ii < rscale_texts->num_elements; ii++) { + const char **stored, *p1, *p2; + + stored = icalarray_element_at(rscale_texts, ii); + if(!stored || !*stored) + continue; + + for(p1 = *stored, p2 = text; *p1 && *p2; p1++, p2++) { + if (tolower(*p1) != tolower(*p2)) + break; + } + + if(!*p1 && !*p2) { + res = *stored; + break; + } + } + +#if defined(HAVE_PTHREAD) + pthread_mutex_unlock(&rscale_texts_mutex); +#endif + + return res; +} + +static const char *match_or_add_rscale_text(const char *text) +{ + const char *res; + + if(!text) { + return NULL; + } + + res = match_rscale_text (text); + +#if defined(HAVE_PTHREAD) + pthread_mutex_lock(&rscale_texts_mutex); +#endif + + if(!res && rscale_texts) { + res = icalmemory_strdup(text); + icalarray_append(rscale_texts, &res); + } + +#if defined(HAVE_PTHREAD) + pthread_mutex_unlock(&rscale_texts_mutex); +#endif + + return res; +} + +void icalrecur_free_rscale_texts(void) +{ +#if defined(HAVE_PTHREAD) + pthread_mutex_lock(&rscale_texts_mutex); +#endif + + if(rscale_texts) { + size_t ii; + for(ii = 0; rscale_texts && ii < rscale_texts->num_elements; ii++) { + char **stored; + + stored = icalarray_element_at(rscale_texts, ii); + if(stored && *stored) + icalmemory_free_buffer(*stored); + } + + icalarray_free(rscale_texts); + rscale_texts = NULL; + } + +#if defined(HAVE_PTHREAD) + pthread_mutex_unlock(&rscale_texts_mutex); +#endif +} + int icalrecurrencetype_rscale_is_supported(void) { return RSCALE_IS_SUPPORTED; @@ -585,7 +719,7 @@ struct icalrecurrencetype icalrecurrence if (parser.rt.freq == ICAL_NO_RECURRENCE) r = -1; } else if (icalrecurrencetype_rscale_is_supported() && strcasecmp(name, "RSCALE") == 0) { - parser.rt.rscale = icalmemory_tmp_copy(value); + parser.rt.rscale = match_or_add_rscale_text(value); } else if (icalrecurrencetype_rscale_is_supported() && strcasecmp(name, "SKIP") == 0) { parser.rt.skip = icalrecur_string_to_skip(value); @@ -1359,19 +1493,16 @@ static int initialize_iterator(icalrecur impl->greg = NULL; } else { UEnumeration *en; - const char *cal; - char *r; + const char *cal, *rrscale; - /* Lowercase the specified calendar */ - for (r = rule.rscale; *r; r++) { - *r = tolower((int)*r); - } + /* This can be a user-created string, thus not a one from the pool */ + rrscale = match_or_add_rscale_text (rule.rscale); /* Check if specified calendar is supported */ en = ucal_getKeywordValuesForLocale("calendar", NULL, FALSE, &status); while ((cal = uenum_next(en, NULL, &status))) { - if (!strcmp(cal, rule.rscale)) { - is_hebrew = !strcmp(rule.rscale, "hebrew"); + if (rrscale == match_rscale_text(cal)) { + is_hebrew = rrscale == match_rscale_text("hebrew"); break; } } diff -up libical-2.0.0/src/libical/icalrecur.h.rscale libical-2.0.0/src/libical/icalrecur.h --- libical-2.0.0/src/libical/icalrecur.h.rscale 2016-02-11 14:08:38.754473804 +0100 +++ libical-2.0.0/src/libical/icalrecur.h 2016-02-11 14:51:58.542361856 +0100 @@ -181,7 +181,7 @@ struct icalrecurrencetype short by_set_pos[ICAL_BY_SETPOS_SIZE]; /* For RSCALE extension (RFC 7529) */ - char *rscale; + const char *rscale; icalrecurrencetype_skip skip; }; @@ -191,6 +191,12 @@ LIBICAL_ICAL_EXPORT icalarray *icalrecur LIBICAL_ICAL_EXPORT void icalrecurrencetype_clear(struct icalrecurrencetype *r); +/* Frees pool of calendar names used by icalrecurrencetype::rscale. + * Do not call if anything else can use it (like components or other + * icalrecurrencetype structures). + */ +LIBICAL_ICAL_EXPORT void icalrecur_free_rscale_texts(void); + /** * Array Encoding *