]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Allow access to headers from INVITE
authorTravis Cross <tc@traviscross.com>
Fri, 21 Feb 2014 20:45:22 +0000 (20:45 +0000)
committerTravis Cross <tc@traviscross.com>
Fri, 21 Feb 2014 20:45:40 +0000 (20:45 +0000)
This adds a sip profile parameter parse-all-invite-headers that when
set parses all headers from an INVITE into channel variables.  The
headers are converted to lowercase, underscores are replaced with
dashes, and the result is prefixed with sip_i_.  Headers than exist
more than once are set as arrays.

FS-6075 --resolve

Thanks-to: Peter Olsson <peter@olssononline.se>
src/mod/endpoints/mod_sofia/mod_sofia.h
src/mod/endpoints/mod_sofia/sofia.c

index b600822bd3ea6fcda83161f044067e50f2d4679a..54beceb3fdb4689c382b00186e3b91b25830417f 100644 (file)
@@ -271,6 +271,7 @@ typedef enum {
        PFLAG_TCP_PINGPONG,
        PFLAG_TCP_PING2PONG,
        PFLAG_MESSAGES_RESPOND_200_OK,
+       PFLAG_PARSE_ALL_INVITE_HEADERS,
        /* No new flags below this line */
        PFLAG_MAX
 } PFLAGS;
index a3db892176756e46e0a76bce7d943ed00dea480c..cf4e5a526765fccc716052ec4e94333a9a0256f9 100644 (file)
@@ -325,7 +325,196 @@ static void extract_vars(sofia_profile_t *profile, sip_t const *sip,
        }
 }
 
+/**
+ * Add a specific SIP INVITE header to the channel variables, prefixed with "sip_i_"
+ */
+static void sofia_add_invite_header_to_chanvars(switch_channel_t *channel, nua_handle_t *nh, void *sip_header, const char *var)
+{
+       switch_assert(channel);
+       switch_assert(nh);
+       switch_assert(var);
+
+       if (sip_header) {
+               char *full;
+               if ((full = sip_header_as_string(nh->nh_home, sip_header))) {
+                       switch_channel_set_variable(channel, var, full);
+                       su_free(nh->nh_home, full);
+               }
+       }
+}
+
+/**
+ * Deep search into the SIP message to recreate the original headers, including multiple Diversions, etc.
+ * Finally sets the "sip_invite_headers" to a string containing the 'original' SIP headers, except that the order may have changed.
+ * Multiple headers will have the original internal order, though.
+ *
+ * @param sip A sip_t struct containing the parsed message
+ * @param session A call session
+ * @param nh A NUA handle for string allocation
+ */
+static void sofia_parse_all_invite_headers(sip_t const *sip, switch_core_session_t *session, nua_handle_t *nh)
+{
+       switch_channel_t *channel = switch_core_session_get_channel(session);
+       sip_unknown_t *un;
+       sip_p_asserted_identity_t *passerted;
+       sip_p_preferred_identity_t *ppreferred;
+       sip_remote_party_id_t *rpid;
+       sip_reply_to_t *reply_to;
+       sip_alert_info_t *alert_info;
+
+       if (!sip) return;
+
+       /* Add simple (unique) headers first */
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_from, "sip_i_from");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_to, "sip_i_to");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_call_id, "sip_i_call_id");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_cseq, "sip_i_cseq");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_route, "sip_i_route");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_max_forwards, "sip_i_max_forwards");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_proxy_require, "sip_i_proxy_require");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_contact, "sip_i_contact");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_user_agent, "sip_i_user_agent");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_subject, "sip_i_subject");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_priority, "sip_i_priority");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_organization, "sip_i_organization");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_in_reply_to, "sip_i_in_reply_to");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_accept_encoding, "sip_i_accept_encoding");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_accept_language, "sip_i_accept_language");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_allow, "sip_i_allow");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_require, "sip_i_require");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_supported, "sip_i_supported");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_date, "sip_i_date");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_timestamp, "sip_i_timestamp");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_expires, "sip_i_expires");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_min_expires, "sip_i_min_expires");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_session_expires, "sip_i_session_expires");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_min_se, "sip_i_min_se");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_privacy, "sip_i_privacy");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_mime_version, "sip_i_mime_version");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_type, "sip_i_content_type");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_encoding, "sip_i_content_encoding");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_language, "sip_i_content_language");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_disposition, "sip_i_content_disposition");
+       sofia_add_invite_header_to_chanvars(channel, nh, sip->sip_content_length, "sip_i_content_length");
+
+       /* Add all other headers - which might exist more than once */
+
+       if (sip->sip_via) {
+               sip_via_t *vp;
+               for (vp = sip->sip_via; vp; vp = vp->v_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_via", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
 
+       if (sip->sip_record_route) {
+               sip_record_route_t *rrp;
+               for (rrp = sip->sip_record_route; rrp; rrp = rrp->r_next) {
+                       char *rr = sip_header_as_string(nh->nh_home, (void *) rrp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_record_route", rr, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, rr);
+               }
+       }
+
+       if (sip->sip_proxy_authorization) {
+               sip_proxy_authorization_t *vp;
+               for (vp = sip->sip_proxy_authorization; vp; vp = vp->au_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_proxy_authorization", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       if (sip->sip_call_info) {
+               sip_call_info_t *vp;
+               for (vp = sip->sip_call_info; vp; vp = vp->ci_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_call_info", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       if (sip->sip_accept) {
+               sip_accept_t *vp;
+               for (vp = sip->sip_accept; vp; vp = vp->ac_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_accept", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       if (sip->sip_authorization) {
+               sip_authorization_t *vp;
+               for (vp = sip->sip_authorization; vp; vp = vp->au_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_authorization", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       if ((alert_info = sip_alert_info(sip))) {
+               sip_alert_info_t *vp;
+               for (vp = alert_info; vp; vp = vp->ai_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_alert_info", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       if ((passerted = sip_p_asserted_identity(sip))) {
+               sip_p_asserted_identity_t *vp;
+               for (vp = passerted; vp; vp = vp->paid_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_p_asserted_identity", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       if ((ppreferred = sip_p_preferred_identity(sip))) {
+               sip_p_preferred_identity_t *vp;
+               for (vp = ppreferred; vp; vp = vp->ppid_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_p_preferred_identity", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       if ((rpid = sip_remote_party_id(sip))) {
+               sip_remote_party_id_t *vp;
+               for (vp = rpid; vp; vp = vp->rpid_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_remote_party_id", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       if ((reply_to = sip_reply_to(sip))) {
+               sip_reply_to_t *vp;
+               for (vp = reply_to; vp; vp = vp->rplyto_next) {
+                       char *v = sip_header_as_string(nh->nh_home, (void *) vp);
+                       switch_channel_add_variable_var_check(channel, "sip_i_reply_to", v, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                       su_free(nh->nh_home, v);
+               }
+       }
+
+       /* Loop through the unknown headers */
+       for (un = sip->sip_unknown; un; un = un->un_next) {
+               if (!zstr(un->un_name) && !zstr(un->un_value)) {
+                       char *parsed_name;
+                       if ((parsed_name = switch_mprintf("sip_i_%s", un->un_name))) {
+                               char *p, *x = parsed_name;
+                               switch_tolower_max(x);
+                               while ((p = strchr(x, '-'))) {
+                                       *p = '_';
+                                       x = ++p;
+                               }
+                               switch_channel_add_variable_var_check(channel, parsed_name, un->un_value, SWITCH_FALSE, SWITCH_STACK_PUSH);
+                               free(parsed_name);
+                       }
+               }
+       }
+}
 
 void sofia_handle_sip_i_notify(switch_core_session_t *session, int status,
                                                           char const *phrase,
@@ -4546,6 +4735,12 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name)
                                                } else {
                                                        sofia_clear_flag(profile, TFLAG_ENABLE_SOA);
                                                }
+                                       } else if (!strcasecmp(var, "parse-all-invite-headers")) {
+                                               if (switch_true(val)) {
+                                                       sofia_set_pflag(profile, PFLAG_PARSE_ALL_INVITE_HEADERS);
+                                               } else {
+                                                       sofia_clear_pflag(profile, PFLAG_PARSE_ALL_INVITE_HEADERS);
+                                               }
                                        } else if (!strcasecmp(var, "bitpacking")) {
                                                if (!strcasecmp(val, "aal2")) {
                                                        profile->codec_flags = SWITCH_CODEC_FLAG_AAL2;
@@ -9139,6 +9334,10 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia
                sofia_presence_set_chat_hash(tech_pvt, sip);
        }
 
+       if (sofia_test_pflag(profile, PFLAG_PARSE_ALL_INVITE_HEADERS)) {
+               sofia_parse_all_invite_headers(sip, session, nh);
+       }
+
        if (sip->sip_to) {
                to = sip->sip_to->a_url;
        }