+uschar *
+string_localpart_alabel_to_utf8(const uschar * alabel, uschar ** err)
+{
+if (string_is_alabel(alabel))
+ return string_localpart_alabel_to_utf8_(alabel, err);
+
+if (err) *err = US"bad alabel prefix";
+return NULL;
+}
+
+
+/**************************************************/
+/* Whole address conversion.
+The *err string pointer should be null before the call.
+
+Return NULL on error, with (optional) errstring pointer filled in
+*/
+
+uschar *
+string_address_utf8_to_alabel(const uschar * utf8, uschar ** err)
+{
+uschar * l, * d;
+
+if (!*utf8) return string_copy(utf8);
+
+DEBUG(D_expand) debug_printf("addr from utf8 <%s>", utf8);
+
+for (const uschar * s = utf8; *s; s++)
+ if (*s == '@')
+ {
+ l = string_copyn(utf8, s - utf8);
+ if ( !(l = string_localpart_utf8_to_alabel(l, err))
+ || !(d = string_domain_utf8_to_alabel(++s, err))
+ )
+ return NULL;
+ l = string_sprintf("%s@%s", l, d);
+ DEBUG(D_expand) debug_printf(" -> <%s>\n", l);
+ return l;
+ }
+
+l = string_localpart_utf8_to_alabel(utf8, err);
+DEBUG(D_expand) debug_printf(" -> <%s>\n", l);
+return l;
+}
+
+
+
+/*************************************************
+* Report the library versions. *
+*************************************************/
+
+/* See a description in tls-openssl.c for an explanation of why this exists.
+
+Arguments: a FILE* to print the results to
+Returns: nothing
+*/
+
+void
+utf8_version_report(FILE *f)
+{
+#ifdef SUPPORT_I18N_2008
+fprintf(f, "Library version: IDN2: Compile: %s\n"
+ " Runtime: %s\n",
+ IDN2_VERSION,
+ idn2_check_version(NULL));
+fprintf(f, "Library version: Stringprep: Compile: %s\n"
+ " Runtime: %s\n",
+ STRINGPREP_VERSION,
+ stringprep_check_version(NULL));
+#else
+fprintf(f, "Library version: IDN: Compile: %s\n"
+ " Runtime: %s\n",
+ STRINGPREP_VERSION,
+ stringprep_check_version(NULL));
+#endif
+}
+