--- /dev/null
+From 472086370630e1547cf9b497295b4a53d811e872 Mon Sep 17 00:00:00 2001
+From: Sebastian Kemper <sebastian_ml@gmx.net>
+Date: Sun, 17 Oct 2021 20:17:57 +0200
+Subject: [PATCH] time: add support for time64 libc
+
+libcs are implementing changes to fix the year 2038 issue on 32 bit
+platforms (see [1]). musl libc already went ahead and implemented it,
+starting with musl-1.2.0 (see [2]).
+
+Running asterisk on a 32 bit box with a time64 libc causes some
+problems. For instance registering to pjsip doesn't work. The
+registration completes fine, but the AOR disappears immediately, making
+the registered clients unreachable.
+
+This commit adds two new definitions to include/asterisk/time.h:
+
+TIME_T_INT_FMT
+TIME_T_UINT_FMT
+
+If __USE_TIME_BITS64 is defined (by a time64 libc, see [1]), they're set
+to the proper conversions for type int64_t, PRId64 and PRIu64
+respectively. If __USE_TIME_BITS64 is not defined, the status quo
+remains unchanged ("%ld" and "%lu" are used).
+
+The new definitions are used in the different parts of asterisk, where
+appropriate.
+
+These changes get rid of the new warnings that appeared with musl-1.2.0 and
+make the pjsip registration work again. Below an example warning:
+
+In file included from ../include/asterisk.h:23,
+ from res_pjsip/location.c:19:
+res_pjsip/location.c: In function 'expiration_struct2str':
+../include/asterisk/astmm.h:270:72: warning: format '%ld' expects argument of type 'long int', but argument 6 has type 'time_t' {aka 'long long int'} [-Wformat=]
+ 270 | __ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, (ret), (fmt), __VA_ARGS__)
+ | ^~~~~
+res_pjsip/location.c:492:17: note: in expansion of macro 'ast_asprintf'
+ 492 | return (ast_asprintf(buf, "%ld", contact->expiration_time.tv_sec) < 0) ? -1 : 0;
+ | ^~~~~~~~~~~~
+
+[1] https://sourceware.org/glibc/wiki/Y2038ProofnessDesign
+[2] https://musl.libc.org/time64.html
+
+ASTERISK-29674 #close
+
+Signed-off-by: Sebastian Kemper <sebastian_ml@gmx.net>
+Change-Id: Ic8d61b26033f5c486b917e738c9608b0923a844e
+---
+ include/asterisk/time.h | 16 ++++++++++++++++
+ res/res_calendar_caldav.c | 2 +-
+ res/res_calendar_icalendar.c | 2 +-
+ res/res_http_media_cache.c | 4 ++--
+ res/res_odbc.c | 2 +-
+ res/res_pjsip/location.c | 2 +-
+ res/res_pjsip/pjsip_options.c | 2 +-
+ res/res_pjsip_history.c | 12 ++++++------
+ res/res_pjsip_pubsub.c | 2 +-
+ res/res_pjsip_registrar.c | 2 +-
+ res/res_stir_shaken.c | 2 +-
+ 11 files changed, 32 insertions(+), 16 deletions(-)
+
+--- a/include/asterisk/time.h
++++ b/include/asterisk/time.h
+@@ -29,6 +29,22 @@
+ #include <sys/time.h>
+ #endif
+
++#ifndef TIME_T_INT_FMT
++#ifdef __USE_TIME_BITS64
++#define TIME_T_INT_FMT PRId64
++#else
++#define TIME_T_INT_FMT "ld"
++#endif
++#endif
++
++#ifndef TIME_T_UINT_FMT
++#ifdef __USE_TIME_BITS64
++#define TIME_T_UINT_FMT PRIu64
++#else
++#define TIME_T_UINT_FMT "lu"
++#endif
++#endif
++
+ #ifdef HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+--- a/res/res_calendar_caldav.c
++++ b/res/res_calendar_caldav.c
+@@ -405,7 +405,7 @@ static void caldav_add_event(icalcompone
+ ast_string_field_set(event, uid, event->summary);
+ } else {
+ char tmp[100];
+- snprintf(tmp, sizeof(tmp), "%ld", event->start);
++ snprintf(tmp, sizeof(tmp), "%" TIME_T_INT_FMT, event->start);
+ ast_string_field_set(event, uid, tmp);
+ }
+ }
+--- a/res/res_calendar_icalendar.c
++++ b/res/res_calendar_icalendar.c
+@@ -246,7 +246,7 @@ static void icalendar_add_event(icalcomp
+ ast_string_field_set(event, uid, event->summary);
+ } else {
+ char tmp[100];
+- snprintf(tmp, sizeof(tmp), "%ld", event->start);
++ snprintf(tmp, sizeof(tmp), "%" TIME_T_INT_FMT, event->start);
+ ast_string_field_set(event, uid, tmp);
+ }
+ }
+--- a/res/res_http_media_cache.c
++++ b/res/res_http_media_cache.c
+@@ -152,7 +152,7 @@ static void bucket_file_set_expiration(s
+ }
+
+ /* Use 'now' if we didn't get an expiration time */
+- snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec);
++ snprintf(time_buf, sizeof(time_buf), "%30" TIME_T_UINT_FMT, actual_expires.tv_sec);
+
+ ast_bucket_file_metadata_set(bucket_file, "__actual_expires", time_buf);
+ }
+@@ -302,7 +302,7 @@ static int bucket_file_expired(struct as
+ return 1;
+ }
+
+- if (sscanf(metadata->value, "%lu", &expires.tv_sec) != 1) {
++ if (sscanf(metadata->value, "%" TIME_T_UINT_FMT, &expires.tv_sec) != 1) {
+ return 1;
+ }
+
+--- a/res/res_odbc.c
++++ b/res/res_odbc.c
+@@ -1038,7 +1038,7 @@ static odbc_status odbc_obj_connect(stru
+ /* Dont connect while server is marked as unreachable via negative_connection_cache */
+ negative_cache_expiration = obj->parent->last_negative_connect.tv_sec + obj->parent->negative_connection_cache.tv_sec;
+ if (time(NULL) < negative_cache_expiration) {
+- ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %ld seconds\n", obj->parent->name, negative_cache_expiration - time(NULL));
++ ast_log(LOG_WARNING, "Not connecting to %s. Negative connection cache for %" TIME_T_INT_FMT " seconds\n", obj->parent->name, negative_cache_expiration - time(NULL));
+ return ODBC_FAIL;
+ }
+
+--- a/res/res_pjsip/location.c
++++ b/res/res_pjsip/location.c
+@@ -489,7 +489,7 @@ static int expiration_str2struct(const s
+ static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf)
+ {
+ const struct ast_sip_contact *contact = obj;
+- return (ast_asprintf(buf, "%ld", contact->expiration_time.tv_sec) < 0) ? -1 : 0;
++ return (ast_asprintf(buf, "%" TIME_T_INT_FMT, contact->expiration_time.tv_sec) < 0) ? -1 : 0;
+ }
+
+ static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags)
+--- a/res/res_pjsip/pjsip_options.c
++++ b/res/res_pjsip/pjsip_options.c
+@@ -2733,7 +2733,7 @@ int ast_sip_format_contact_ami(void *obj
+ ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id);
+ ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri);
+ ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent);
+- ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec);
++ ast_str_append(&buf, 0, "RegExpire: %" TIME_T_INT_FMT "\r\n", contact->expiration_time.tv_sec);
+ if (!ast_strlen_zero(contact->via_addr)) {
+ ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr);
+ if (contact->via_port) {
+--- a/res/res_pjsip_history.c
++++ b/res/res_pjsip_history.c
+@@ -199,7 +199,7 @@ static int evaluate_equal(struct operato
+ {
+ struct timeval right = { 0, };
+
+- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) {
++ if (sscanf(op_right->field, "%" TIME_T_INT_FMT, &right.tv_sec) != 1) {
+ ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
+ return -1;
+ }
+@@ -270,7 +270,7 @@ static int evaluate_less_than(struct ope
+ {
+ struct timeval right = { 0, };
+
+- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) {
++ if (sscanf(op_right->field, "%" TIME_T_INT_FMT, &right.tv_sec) != 1) {
+ ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
+ return -1;
+ }
+@@ -319,7 +319,7 @@ static int evaluate_greater_than(struct
+ {
+ struct timeval right = { 0, };
+
+- if (sscanf(op_right->field, "%ld", &right.tv_sec) != 1) {
++ if (sscanf(op_right->field, "%" TIME_T_INT_FMT, &right.tv_sec) != 1) {
+ ast_log(LOG_WARNING, "Unable to extract field '%s': not a timestamp\n", op_right->field);
+ return -1;
+ }
+@@ -668,7 +668,7 @@ static void sprint_list_entry(struct pjs
+ char uri[128];
+
+ pjsip_uri_print(PJSIP_URI_IN_REQ_URI, entry->msg->line.req.uri, uri, sizeof(uri));
+- snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s %.*s %s SIP/2.0",
++ snprintf(line, len, "%-5.5d %-10.10" TIME_T_INT_FMT " %-5.5s %-24.24s %.*s %s SIP/2.0",
+ entry->number,
+ entry->timestamp.tv_sec,
+ entry->transmitted ? "* ==>" : "* <==",
+@@ -677,7 +677,7 @@ static void sprint_list_entry(struct pjs
+ pj_strbuf(&entry->msg->line.req.method.name),
+ uri);
+ } else {
+- snprintf(line, len, "%-5.5d %-10.10ld %-5.5s %-24.24s SIP/2.0 %u %.*s",
++ snprintf(line, len, "%-5.5d %-10.10" TIME_T_INT_FMT " %-5.5s %-24.24s SIP/2.0 %u %.*s",
+ entry->number,
+ entry->timestamp.tv_sec,
+ entry->transmitted ? "* ==>" : "* <==",
+@@ -1169,7 +1169,7 @@ static void display_single_entry(struct
+ pj_sockaddr_print(&entry->src, addr, sizeof(addr), 3);
+ }
+
+- ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10ld --->\n",
++ ast_cli(a->fd, "<--- History Entry %d %s %s at %-10.10" TIME_T_INT_FMT " --->\n",
+ entry->number,
+ entry->transmitted ? "Sent to" : "Received from",
+ addr,
+--- a/res/res_pjsip_pubsub.c
++++ b/res/res_pjsip_pubsub.c
+@@ -4744,7 +4744,7 @@ static int persistence_expires_str2struc
+ static int persistence_expires_struct2str(const void *obj, const intptr_t *args, char **buf)
+ {
+ const struct subscription_persistence *persistence = obj;
+- return (ast_asprintf(buf, "%ld", persistence->expires.tv_sec) < 0) ? -1 : 0;
++ return (ast_asprintf(buf, "%" TIME_T_INT_FMT, persistence->expires.tv_sec) < 0) ? -1 : 0;
+ }
+
+ #define RESOURCE_LIST_INIT_SIZE 4
+--- a/res/res_pjsip_registrar.c
++++ b/res/res_pjsip_registrar.c
+@@ -1272,7 +1272,7 @@ static void *check_expiration_thread(voi
+ while (check_interval) {
+ sleep(check_interval);
+
+- sprintf(time, "%ld", ast_tvnow().tv_sec);
++ sprintf(time, "%" TIME_T_INT_FMT, ast_tvnow().tv_sec);
+ var = ast_variable_new("expiration_time <=", time, "");
+
+ ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval);
+--- a/res/res_stir_shaken.c
++++ b/res/res_stir_shaken.c
+@@ -389,7 +389,7 @@ static void set_public_key_expiration(co
+ actual_expires.tv_sec += EXPIRATION_BUFFER;
+ }
+
+- snprintf(time_buf, sizeof(time_buf), "%30lu", actual_expires.tv_sec);
++ snprintf(time_buf, sizeof(time_buf), "%30" TIME_T_UINT_FMT, actual_expires.tv_sec);
+
+ ast_db_put(hash, "expiration", time_buf);
+ }