Hi,

Debian has recently switched to libical >= 2.0.0 that hides some
previously exported symbols.

I rewrote custom icalrecur_add_rule to reconstruct RRULE from XML or
JSON to be reparsed again with icalrecurrencetype_from_string(char *).

I understand this is not optimal, but I believe that simplicity of the
code outweights the speed.

And I suggest to drop support for libical << 2.0.0 for simplicity. And
in that case I will weed out the HAVE_ICAL_<foo> macros and send another
patch with that (0018-* is just basic to get it compiled).

Please review (and apply) attached patch. I used buf_* functions to
reconstruct the cstring, but it desperately needs a review if I am using
those correctly and if it doesn't leak memory (it probably does? But in
that case json_x_value leaks it as well).

But hey it compiles! :)

Cheers,
-- 
Ondřej Surý <ond...@sury.org>
Knot DNS (https://www.knot-dns.cz/) – a high-performance DNS server
Knot Resolver (https://www.knot-resolver.cz/) – secure, privacy-aware,
fast DNS(SEC) resolver
Vše pro chleba (https://vseprochleba.cz) – Potřeby pro pečení chleba
všeho druhu
From: =?utf-8?q?Ond=C5=99ej_Sur=C3=BD?= <ond...@sury.org>
Date: Mon, 23 May 2016 23:15:44 +0200
Subject: Replace the custom icalrecur_add_rule() with reconstructing RRULE
 and parsing it with standard icalrecurrencetype_from_string()

---
 imap/jcal.c |  22 ++++++------
 imap/xcal.c | 112 +++++++++++-------------------------------------------------
 2 files changed, 30 insertions(+), 104 deletions(-)

diff --git a/imap/jcal.c b/imap/jcal.c
index 52b2534..98f8f31 100644
--- a/imap/jcal.c
+++ b/imap/jcal.c
@@ -455,10 +455,6 @@ struct icalrecur_parser {
 };
 
 extern icalrecurrencetype_frequency icalrecur_string_to_freq(const char* str);
-extern void icalrecur_add_byrules(struct icalrecur_parser *parser, short *array,
-				  int size, char* vals);
-extern void icalrecur_add_bydayrules(struct icalrecur_parser *parser,
-				     const char* vals);
 
 static const char *_json_x_value(json_t *jvalue)
 {
@@ -549,19 +545,23 @@ static icalvalue *json_object_to_icalvalue(json_t *jvalue,
 
     case ICAL_RECUR_VALUE:
 	if (json_is_object(jvalue)) {
-	    struct icalrecurrencetype *rt = NULL;
+	    struct icalrecurrencetype rt;
+	    static struct buf buf = BUF_INITIALIZER;
 	    const char *key;
 	    json_t *val;
 
 	    json_object_foreach(jvalue, key, val) {
-		rt = icalrecur_add_rule(&rt, key, val,
-		    (int (*)(void *)) &json_integer_value,
-		    (const char * (*)(void *)) &json_x_value);
-		if (!rt) break;
+		buf_appendcstr(&buf, (const char *)key);
+		buf_appendcstr(&buf, "=");
+		buf_appendcstr(&buf, (const char *)json_x_value(val));
+		buf_appendcstr(&buf, ";");
 	    }
 
-            if (rt && rt->freq != ICAL_NO_RECURRENCE)
-		value = icalvalue_new_recur(*rt);
+	    /* Now reparse it with libical function */
+	    rt = icalrecurrencetype_from_string((const char *)buf_cstring(&buf));
+
+            if (rt.freq != ICAL_NO_RECURRENCE)
+		value = icalvalue_new_recur(rt);
 	}
 	else
 	    syslog(LOG_WARNING, "jCal object object expected");
diff --git a/imap/xcal.c b/imap/xcal.c
index e9f73b0..79f30ca 100644
--- a/imap/xcal.c
+++ b/imap/xcal.c
@@ -681,92 +681,6 @@ extern icalrecurrencetype_frequency icalrecur_string_to_freq(const char* str);
 #ifdef HAVE_RSCALE
 extern icalrecurrencetype_skip icalrecur_string_to_skip(const char* str);
 #endif
-extern void icalrecur_add_byrules(struct icalrecur_parser *parser, short *array,
-				  int size, char* vals);
-extern void icalrecur_add_bydayrules(struct icalrecur_parser *parser,
-				     const char* vals);
-
-struct icalrecurrencetype *icalrecur_add_rule(struct icalrecurrencetype **rt,
-					      const char *rpart, void *data,
-					      int (*get_int)(void *),
-					      const char* (*get_str)(void *))
-{
-    static struct icalrecur_parser parser;
-
-    if (!*rt) {
-	/* Initialize */
-	*rt = &parser.rt;
-	icalrecurrencetype_clear(*rt);
-    }
-
-    if (!strcmp(rpart, "freq")) {
-	(*rt)->freq = icalrecur_string_to_freq(get_str(data));
-    }
-#ifdef HAVE_RSCALE
-    else if (!strcmp(rpart, "rscale")) {
-	(*rt)->rscale = icalmemory_tmp_copy(get_str(data));
-    }
-    else if (!strcmp(rpart, "skip")) {
-	(*rt)->skip = icalrecur_string_to_skip(get_str(data));
-    }
-#endif
-    else if (!strcmp(rpart, "count")) {
-	(*rt)->count = get_int(data);
-    }
-    else if (!strcmp(rpart, "until")) {
-	(*rt)->until = icaltime_from_string(get_str(data));
-    }
-    else if (!strcmp(rpart, "interval")) {
-	(*rt)->interval = get_int(data);
-	if ((*rt)->interval < 1) (*rt)->interval = 1;  /* MUST be >= 1 */
-    }
-    else if (!strcmp(rpart, "wkst")) {
-	(*rt)->week_start = icalrecur_string_to_weekday(get_str(data));
-    }
-    else if (!strcmp(rpart, "byday")) {
-	icalrecur_add_bydayrules(&parser, get_str(data));
-    }
-    else {
-	int i;
-
-	for (i = 0; recurmap[i].str && strcmp(rpart, recurmap[i].str); i++);
-
-	if (recurmap[i].str) {
-	    short *array =
-		(short *)((size_t) *rt + recurmap[i].offset);
-	    int limit = recurmap[i].limit;
-
-	    icalrecur_add_byrules(&parser, array, limit,
-				  icalmemory_tmp_copy(get_str(data)));
-	}
-	else {
-	    syslog(LOG_WARNING, "Unknown recurrence rule-part: %s", rpart);
-	    icalrecurrencetype_clear(*rt);
-	    *rt = NULL;
-	}
-    }
-
-#ifdef HAVE_RSCALE
-    /* When "RSCALE" is not present the default is "YES".
-       When "RSCALE" is present the default is "BACKWARD". */
-    if (!(*rt)->rscale) (*rt)->skip = ICAL_SKIP_YES;
-    else if ((*rt)->skip == ICAL_SKIP_NO) (*rt)->skip = ICAL_SKIP_BACKWARD;
-#endif
-
-    return *rt;
-}
-
-
-int xmlElementContent_to_int(void *content)
-{
-    return atoi((const char *) content);
-}
-
-const char *xmlElementContent_to_str(void *content)
-{
-    return (const char *) content;
-}
-
 
 /*
  * Construct an iCalendar property value from XML content.
@@ -868,22 +782,34 @@ static icalvalue *xml_element_to_icalvalue(xmlNodePtr xtype,
     }
 
     case ICAL_RECUR_VALUE: {
-	struct icalrecurrencetype *rt = NULL;
+	static struct buf buf = BUF_INITIALIZER;
+	struct icalrecurrencetype rt;
 
+	buf_reset(&buf);
+
+	char *dst, *str;
+	size_t dst_len = 0, str_len;
+
+	/* First we count required length of the RRULE string */
 	for (node = xmlFirstElementChild(xtype); node;
 	     node = xmlNextElementSibling(node)) {
 
 	    content = xmlNodeGetContent(node);
-	    rt = icalrecur_add_rule(&rt, (const char *) node->name, content,
-				    &xmlElementContent_to_int,
-				    &xmlElementContent_to_str);
+
+	    buf_appendcstr(&buf, (const char *)node->name);
+	    buf_appendcstr(&buf, (const char *)"=");
+	    buf_appendcstr(&buf, (const char *)content);
+	    buf_appendcstr(&buf, (const char *)";");
+
 	    xmlFree(content);
 	    content = NULL;
-	    if (!rt) break;
 	}
 
-	if (rt && rt->freq != ICAL_NO_RECURRENCE)
-	    value = icalvalue_new_recur(*rt);
+	/* Now reparse it with libical function */
+	rt = icalrecurrencetype_from_string((const char *)buf_cstring(&buf));
+
+	if (rt.freq != ICAL_NO_RECURRENCE)
+	    value = icalvalue_new_recur(rt);
 
 	break;
     }
From: =?utf-8?q?Ond=C5=99ej_Sur=C3=BD?= <ond...@sury.org>
Date: Fri, 13 May 2016 15:27:35 +0200
Subject: Require libical >= 2.0 and define the libical feature macros
 according to that

---
 configure.ac | 22 +++++++++-------------
 1 file changed, 9 insertions(+), 13 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8e460d3..cfeb4de 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1209,7 +1209,7 @@ dnl
 	ENABLE_RSS=yes
 	ENABLE_DAV=yes
 	PKG_CHECK_MODULES([XML2], [libxml-2.0],,AC_MSG_ERROR([Need libxml-2.0 for http]))
-	PKG_CHECK_MODULES([ICAL], [libical],,AC_MSG_ERROR([Need libical for http]))
+	PKG_CHECK_MODULES([ICAL], [libical >= 2.0],,AC_MSG_ERROR([Need libical >= 2.0.0 for http]))
 	PKG_CHECK_MODULES([SQLITE3], [sqlite3],,AC_MSG_ERROR([Need sqlite3 for http]))
 	PKG_CHECK_MODULES([JSON], [jansson],,AC_MSG_ERROR([Need jansson for http]))
 
@@ -1227,9 +1227,8 @@ dnl
 		AC_DEFINE(HAVE_TZ_BY_REF,[],
 			[Build TZ by ref support into httpd?]))
 
-	AC_EGREP_HEADER(ICAL_TZUNTIL_PROPERTY, ical.h,
-		AC_DEFINE(HAVE_TZDIST_PROPS,[],
-			[Do we have built-in support for TZdist props?]))
+	AC_DEFINE(HAVE_TZDIST_PROPS,[],
+		[Do we have built-in support for TZdist props?])
 
 	CYRUS_OPENDKIM_CHK()
 	if test "$opendkimlib" = "yes"; then
@@ -1238,17 +1237,14 @@ dnl
 	    AC_DEFINE(WITH_DKIM,[],[Build DKIM support into iSchedule?]) 
 	fi
 
-	AC_EGREP_HEADER(ICAL_SCHEDULESTATUS_PARAMETER, ical.h,
-		AC_DEFINE(HAVE_SCHEDULING_PARAMS,[],
-			[Do we have built-in support for scheduling params?]))
+	AC_DEFINE(HAVE_SCHEDULING_PARAMS,[],
+		[Do we have built-in support for scheduling params?])
 
-	AC_EGREP_HEADER(ICAL_VAVAILABILITY_COMPONENT, ical.h,
-		AC_DEFINE(HAVE_VAVAILABILITY,[],
-			[Build VAVAILABILITY support into httpd?]))
+	AC_DEFINE(HAVE_VAVAILABILITY,[],
+		[Build VAVAILABILITY support into httpd?])
 
-	AC_EGREP_HEADER(ICAL_VPOLL_COMPONENT, ical.h,
-		AC_DEFINE(HAVE_VPOLL,[],
-			[Build VPOLL support into httpd?]))
+	AC_DEFINE(HAVE_VPOLL,[],
+		[Build VPOLL support into httpd?])
 
 	ENABLE_RSCALE=yes
 	PKG_CHECK_MODULES([ICU], [icu-i18n],, ENABLE_RSCALE=no)

Reply via email to