# 03_pjsip_signaling.patch (FULL port from 2.12 — copied verbatim)
#
# Replaces the previous minimal stub. Adds:
#   * pjsip_msg_find_remove_hdr_by_name() — find + erase a SIP header by name
#   * pjsip_print_body()                  — print SIP body into a static buffer
#   * pjsip_evsub_update_expires()        — update subscription refresh time
#   * pjsip_evsub_set_timer()             — schedule a refresh timer
#   * parse_hdr_allow_events()            — Allow-Events header parser
#   * sip_inv.c: accept SDP only in specific message types; tolerate
#                LOCAL_OFFER state when caller has a pending offer
#   * sip_transport_tls.c: tls_name parameter through tls_create() so
#                          callers can override the SNI / server-name
#                          used by OpenSSL verification (folded in from
#                          28_pjsip_tls_lis_create_*.patch in 2.12)
#
# The 2.12 patch was written against pjproject 2.10. pjsip 2.17 has
# significant line drift (RFC 6026 changes, 2.14 INVITE/dialog rework,
# 2.13 whitespace sweep). Many hunks will apply with offsets/fuzz under
# `patch -l --fuzz=2`. Hunks that REJECT will need targeted rebase —
# paste the reject and we'll fix per-hunk.
diff -ruN pjproject-2.10/pjsip/include/pjsip/sip_msg.h pjsip/pjsip/include/pjsip/sip_msg.h
--- pjproject-2.10/pjsip/include/pjsip/sip_msg.h	2020-02-14 10:48:27.000000000 +0100
+++ pjsip/pjsip/include/pjsip/sip_msg.h	2021-02-06 19:48:20.570302003 +0100
@@ -675,6 +675,23 @@
 };

 /**
+ * General purpose function to print a SIP message body.
+ * Uses the appropriate internal functions to print the string representation
+ * of a SIP message body. It sets the output buffer to a statically allocated
+ * buffer, so the caller is responsible to copy it.
+ *
+ * @param msg_body     The message body.
+ * @param buf          Pointer to get the result buffer (statically allocated).
+ * @param size         The size of the buffer.
+ *
+ * @return             The length copied to the buffer, or -1.
+ */
+PJ_DECL(int) pjsip_print_body( pjsip_msg_body *msg_body,
+                                   char **buf, int *len);
+
+
+
+/**
  * General purpose function to textual data in a SIP body. Attach this function
  * in a SIP message body only if the data in pjsip_msg_body is a textual
  * message ready to be embedded in a SIP message. If the data in the message
@@ -894,6 +911,20 @@
 PJ_DECL(void*)  pjsip_msg_find_remove_hdr( pjsip_msg *msg,
 					   pjsip_hdr_e hdr, void *start);

+/**
+ * Find and remove a header in the message.
+ *
+ * @param msg      The message.
+ * @param name     The header name to find.
+ * @param start            The first header field where the search should begin,
+ *                 or NULL to search from the first header in the message.
+ *
+ * @return         The header field, or NULL if not found.
+ */
+PJ_DECL(void*)  pjsip_msg_find_remove_hdr_by_name( pjsip_msg *msg,
+                                                   pj_str_t *name,
+                                                   void *start);
+
 /**
  * Add a header to the message, putting it last in the header list.
  *
diff -ruN pjproject-2.10/pjsip/include/pjsip-simple/evsub.h pjsip/pjsip/include/pjsip-simple/evsub.h
--- pjproject-2.10/pjsip/include/pjsip-simple/evsub.h	2020-02-14 10:48:27.000000000 +0100
+++ pjsip/pjsip/include/pjsip-simple/evsub.h	2021-02-06 19:49:09.127691820 +0100
@@ -524,6 +524,18 @@
 					 pj_uint32_t seconds);


+/* Update evbsub internal refresh_time with the given interval */
+PJ_DECL(void) pjsip_evsub_update_expires( pjsip_evsub *sub,
+                                          pj_uint32_t interval );
+
+
+/* Set the specified timer (UAC or UAS) to the specified time */
+PJ_DECL(void) pjsip_evsub_set_timer( pjsip_evsub *sub,
+                                     int timer_id,
+                                     pj_int32_t seconds );
+
+
+
 PJ_END_DECL

 /**
diff -ruN pjproject-2.10/pjsip/src/pjsip/sip_msg.c pjsip/pjsip/src/pjsip/sip_msg.c
--- pjproject-2.10/pjsip/src/pjsip/sip_msg.c	2020-02-14 10:48:27.000000000 +0100
+++ pjsip/pjsip/src/pjsip/sip_msg.c	2021-02-06 19:39:21.510782607 +0100
@@ -394,6 +394,18 @@
     return hdr;
 }

+PJ_DEF(void*) pjsip_msg_find_remove_hdr_by_name( pjsip_msg *msg,
+                                                 pj_str_t *name,
+                                                 void *start)
+{
+    pjsip_hdr *hdr = (pjsip_hdr*) pjsip_msg_find_hdr_by_name(msg, name, start);
+    if (hdr) {
+       pj_list_erase(hdr);
+    }
+    return hdr;
+}
+
+
 PJ_DEF(pj_ssize_t) pjsip_msg_print( const pjsip_msg *msg,
 				    char *buf, pj_size_t size)
 {
@@ -2146,6 +2158,21 @@
 /*
  * Message body manipulations.
  */
+
+PJ_DEF(int) pjsip_print_body(pjsip_msg_body *msg_body, char **buf, int *len)
+{
+    static char s_buf[PJSIP_MAX_PKT_LEN];
+    int res;
+
+    res = (*msg_body->print_body)(msg_body, s_buf, PJSIP_MAX_PKT_LEN);
+    if (res < 0) {
+        return -1;
+    }
+    *buf = s_buf;
+    *len = res;
+    return 0;
+}
+
 PJ_DEF(int) pjsip_print_text_body(pjsip_msg_body *msg_body, char *buf, pj_size_t size)
 {
     if (size < msg_body->len)
diff -ruN pjproject-2.10/pjsip/src/pjsip-simple/evsub.c pjsip/pjsip/src/pjsip-simple/evsub.c
--- pjproject-2.10/pjsip/src/pjsip-simple/evsub.c	2020-02-14 10:48:27.000000000 +0100
+++ pjsip/pjsip/src/pjsip-simple/evsub.c	2021-02-06 19:40:40.321065814 +0100
@@ -495,6 +495,12 @@
 }


+PJ_DEF(void) pjsip_evsub_update_expires( pjsip_evsub *sub, pj_uint32_t interval )
+{
+    update_expires(sub, interval);
+}
+
+
 /*
  * Schedule timer.
  */
@@ -538,6 +544,13 @@
 }


+PJ_DEF(void) pjsip_evsub_set_timer( pjsip_evsub *sub, int timer_id,
+                                   pj_int32_t seconds)
+{
+    set_timer(sub, timer_id, seconds);
+}
+
+
 /*
  * Destructor.
  */
diff -ruN pjproject-2.10/pjsip/src/pjsip-simple/evsub_msg.c pjsip/pjsip/src/pjsip-simple/evsub_msg.c
--- pjproject-2.10/pjsip/src/pjsip-simple/evsub_msg.c	2020-02-14 10:48:27.000000000 +0100
+++ pjsip/pjsip/src/pjsip-simple/evsub_msg.c	2021-02-06 19:41:44.190911650 +0100
@@ -293,6 +293,45 @@
 }

 /*
+ * Parse Allow-Events header.
+ */
+static pjsip_hdr* parse_hdr_allow_events(pjsip_parse_ctx *ctx)
+{
+    pjsip_allow_events_hdr *allow_events =
+             pjsip_allow_events_hdr_create(ctx->pool);
+    const pjsip_parser_const_t *pc = pjsip_parser_const();
+    pj_scanner *scanner = ctx->scanner;
+
+    /* Some header fields allow empty elements in the value:
+     *   Accept, Allow, Supported
+     */
+    if (pj_scan_is_eof(scanner) ||
+    *scanner->curptr == '\r' || *scanner->curptr == '\n')
+    {
+    goto end;
+    }
+
+    pj_scan_get( scanner, &pc->pjsip_NOT_COMMA_OR_NEWLINE,
+             &allow_events->values[0]);
+    allow_events->count++;
+
+    while (*scanner->curptr == ',') {
+    pj_scan_get_char(scanner);
+    pj_scan_get( scanner, &pc->pjsip_NOT_COMMA_OR_NEWLINE,
+             &allow_events->values[allow_events->count]);
+    allow_events->count++;
+
+    if (allow_events->count >= PJSIP_MAX_ALLOW_EVENTS)
+        break;
+    }
+
+end:
+    pjsip_parse_end_hdr_imp(scanner);
+    return (pjsip_hdr*)allow_events;
+}
+
+
+/*
  * Register header parsers.
  */
 PJ_DEF(void) pjsip_evsub_init_parser(void)
diff -ruN pjproject-2.10/pjsip/src/pjsip-ua/sip_inv.c pjsip/pjsip/src/pjsip-ua/sip_inv.c
--- pjproject-2.10/pjsip/src/pjsip-ua/sip_inv.c	2020-02-14 10:48:27.000000000 +0100
+++ pjsip/pjsip/src/pjsip-ua/sip_inv.c	2021-02-06 19:46:19.602835344 +0100
@@ -2006,6 +2006,20 @@
 	return PJMEDIA_SDP_EINSDP;
     }

+    /* Only accept SDP in INVITE, UPDATE and ACK requests, 18x (reliable) and 183 provisional responses
+     * and 200 final response.
+     */
+    if (!(msg->type == PJSIP_REQUEST_MSG && msg->line.req.method.id == PJSIP_INVITE_METHOD) &&
+        !(msg->type == PJSIP_REQUEST_MSG && msg->line.req.method.id == PJSIP_ACK_METHOD) &&
+        !(msg->type == PJSIP_REQUEST_MSG && pjsip_method_cmp(&msg->line.req.method, &pjsip_update_method)==0) &&
+        !(msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code/10==18 && pjsip_100rel_is_reliable(rdata)) &&
+        !(msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code == 183) &&
+        !(msg->type == PJSIP_RESPONSE_MSG && msg->line.status.code == 200)) {
+           PJ_LOG(4,(inv->obj_name, "ignored SDP body"));
+        return PJ_SUCCESS;
+    }
+
+
     /* Get/attach invite session's transaction data */
     tsx_inv_data = (struct tsx_inv_data*) tsx->mod_data[mod_inv.mod.id];
     if (tsx_inv_data == NULL) {
@@ -2233,6 +2247,11 @@
 	{
 	    status = pjmedia_sdp_neg_set_local_answer(inv->pool_prov, inv->neg,
 						      local_sdp);
+	} else if (pjmedia_sdp_neg_get_state(inv->neg)==
+                  PJMEDIA_SDP_NEG_STATE_LOCAL_OFFER)
+       {
+           /* Go forward with our local offer */
+           status = PJ_SUCCESS;
 	} else {

 	    /* Can not specify local SDP at this state. */
