1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Ken Rice <krice at freeswitch.org>
28  * Paul D. Tinsley <pdt at jackhammer.org>
29  * Bret McDanel <trixter AT 0xdecafbad.com>
30  * Raymond Chandler <intralanman@freeswitch.org>
31  * Emmanuel Schmidbauer <eschmidbauer@gmail.com>
32  * Kathleen King <kathleen.king@quentustech.com>
33  *
34  *
35  * mod_sofia.c -- SOFIA SIP Endpoint
36  *
37  */
38 
39 /* Best viewed in a 160 x 60 VT100 Terminal or so the line below at least fits across your screen*/
40 /*************************************************************************************************************************************************************/
41 #include "mod_sofia.h"
42 #include "sofia-sip/sip_extra.h"
43 
44 SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load);
45 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown);
46 SWITCH_MODULE_DEFINITION(mod_sofia, mod_sofia_load, mod_sofia_shutdown, NULL);
47 
48 struct mod_sofia_globals mod_sofia_globals;
49 switch_endpoint_interface_t *sofia_endpoint_interface;
50 
51 #define STRLEN 15
52 
53 void mod_sofia_shutdown_cleanup();
54 static switch_status_t sofia_on_init(switch_core_session_t *session);
55 
56 static switch_status_t sofia_on_exchange_media(switch_core_session_t *session);
57 static switch_status_t sofia_on_soft_execute(switch_core_session_t *session);
58 static switch_status_t sofia_acknowledge_call(switch_core_session_t *session);
59 static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
60 												  switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
61 												  switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
62 static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
63 static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
64 static switch_status_t sofia_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
65 static switch_status_t sofia_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
66 static switch_status_t sofia_read_text_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
67 static switch_status_t sofia_write_text_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
68 static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig);
69 
70 /* BODY OF THE MODULE */
71 /*************************************************************************************************************************************************************/
72 
73 /*
74    State methods they get called when the state changes to the specific state
75    returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
76    so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
77 */
sofia_on_init(switch_core_session_t * session)78 static switch_status_t sofia_on_init(switch_core_session_t *session)
79 {
80 	const char *hval = NULL;
81 	switch_channel_t *channel = switch_core_session_get_channel(session);
82 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
83 	switch_status_t status = SWITCH_STATUS_SUCCESS;
84 
85 	switch_assert(tech_pvt != NULL);
86 
87 
88 	switch_mutex_lock(tech_pvt->sofia_mutex);
89 
90 
91 	switch_core_media_check_dtmf_type(session);
92 
93 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SOFIA INIT\n", switch_channel_get_name(channel));
94 	if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
95 		switch_core_media_absorb_sdp(session);
96 	}
97 
98 	if ((hval = switch_channel_get_variable(channel, "sip_watch_headers"))) {
99 		char *dupvar = NULL;
100 		char *watch_headers[10];
101 		unsigned int numhdrs = 0;
102 		unsigned int i = 0;
103 		dupvar = switch_core_session_strdup(session, hval);
104 		numhdrs = switch_separate_string(dupvar, ',', watch_headers, switch_arraylen(watch_headers));
105 		if (numhdrs) {
106 			char **wheaders = switch_core_session_alloc(session, ((numhdrs+1) * sizeof(wheaders[0])));
107 			for (i = 0; i < numhdrs; i++) {
108 				wheaders[i] = watch_headers[i];
109 			}
110 			wheaders[i] = NULL;
111 			tech_pvt->watch_headers = wheaders;
112 		}
113 	}
114 
115 	if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING) || switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE)) {
116 		sofia_set_flag(tech_pvt, TFLAG_RECOVERED);
117 	}
118 
119 	if (sofia_test_flag(tech_pvt, TFLAG_OUTBOUND) || switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) {
120 		if (sofia_glue_do_invite(session) != SWITCH_STATUS_SUCCESS) {
121 			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
122 			assert(switch_channel_get_state(channel) != CS_INIT);
123 			status = SWITCH_STATUS_FALSE;
124 			goto end;
125 		}
126 	}
127 
128   end:
129 
130 	switch_mutex_unlock(tech_pvt->sofia_mutex);
131 
132 	return status;
133 }
134 
sofia_on_routing(switch_core_session_t * session)135 static switch_status_t sofia_on_routing(switch_core_session_t *session)
136 {
137 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
138 	switch_channel_t *channel = switch_core_session_get_channel(session);
139 	switch_assert(tech_pvt != NULL);
140 
141 	if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTO_INVITE_100) &&
142 		!switch_channel_test_flag(channel, CF_ANSWERED) &&
143 		switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
144 		if (sofia_acknowledge_call(session) != SWITCH_STATUS_SUCCESS) {
145 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Call appears to be already acknowledged\n");
146 		}
147 	}
148 
149 	if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
150 		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
151 		switch_channel_clear_flag(channel, CF_LEG_HOLDING);
152 	}
153 
154 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SOFIA ROUTING\n",
155 					  switch_channel_get_name(switch_core_session_get_channel(session)));
156 
157 	return SWITCH_STATUS_SUCCESS;
158 }
159 
160 
sofia_on_reset(switch_core_session_t * session)161 static switch_status_t sofia_on_reset(switch_core_session_t *session)
162 {
163 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
164 	switch_channel_t *channel = switch_core_session_get_channel(session);
165 	switch_assert(tech_pvt != NULL);
166 
167 	if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
168 		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
169 		switch_channel_clear_flag(channel, CF_LEG_HOLDING);
170 	}
171 
172 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SOFIA RESET\n",
173 					  switch_channel_get_name(switch_core_session_get_channel(session)));
174 
175 
176 	return SWITCH_STATUS_SUCCESS;
177 }
178 
179 
sofia_on_hibernate(switch_core_session_t * session)180 static switch_status_t sofia_on_hibernate(switch_core_session_t *session)
181 {
182 	private_object_t *tech_pvt = switch_core_session_get_private(session);
183 	switch_channel_t *channel = switch_core_session_get_channel(session);
184 	switch_assert(tech_pvt != NULL);
185 
186 	if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
187 		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
188 		switch_channel_clear_flag(channel, CF_LEG_HOLDING);
189 	}
190 
191 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SOFIA HIBERNATE\n",
192 					  switch_channel_get_name(switch_core_session_get_channel(session)));
193 
194 
195 	return SWITCH_STATUS_SUCCESS;
196 }
197 
sofia_on_execute(switch_core_session_t * session)198 static switch_status_t sofia_on_execute(switch_core_session_t *session)
199 {
200 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
201 	switch_channel_t *channel = switch_core_session_get_channel(session);
202 	switch_assert(tech_pvt != NULL);
203 
204 	if (!sofia_test_flag(tech_pvt, TFLAG_HOLD_LOCK)) {
205 		sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
206 		switch_channel_clear_flag(channel, CF_LEG_HOLDING);
207 	}
208 
209 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SOFIA EXECUTE\n",
210 					  switch_channel_get_name(switch_core_session_get_channel(session)));
211 
212 	return SWITCH_STATUS_SUCCESS;
213 }
214 
generate_pai_str(private_object_t * tech_pvt)215 char *generate_pai_str(private_object_t *tech_pvt)
216 {
217 	switch_core_session_t *session = tech_pvt->session;
218 	const char *callee_name = NULL, *callee_number = NULL;
219 	const char *var, *header, *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent");
220 	char *pai = NULL;
221 	const char *host = switch_channel_get_variable(tech_pvt->channel, "sip_to_host");
222 
223 	if (zstr(host)) {
224 		host = tech_pvt->profile->sipip;
225 	}
226 
227 	if (!sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID) || !sofia_test_pflag(tech_pvt->profile, PFLAG_CID_IN_1XX) ||
228 		((var = switch_channel_get_variable(tech_pvt->channel, "sip_cid_in_1xx")) && switch_false(var))) {
229 		return NULL;
230 	}
231 
232 	if (zstr((callee_name = switch_channel_get_variable(tech_pvt->channel, "initial_callee_id_name"))) &&
233 		zstr((callee_name = switch_channel_get_variable(tech_pvt->channel, "effective_callee_id_name"))) &&
234 		zstr((callee_name = switch_channel_get_variable(tech_pvt->channel, "sip_callee_id_name")))) {
235 		callee_name = switch_channel_get_variable(tech_pvt->channel, "callee_id_name");
236 	}
237 
238 	if (zstr((callee_number = switch_channel_get_variable(tech_pvt->channel, "initial_callee_id_number"))) &&
239 		zstr((callee_number = switch_channel_get_variable(tech_pvt->channel, "effective_callee_id_number"))) &&
240 		zstr((callee_number = switch_channel_get_variable(tech_pvt->channel, "sip_callee_id_number"))) &&
241 		zstr((callee_number = switch_channel_get_variable(tech_pvt->channel, "callee_id_number")))) {
242 
243 		callee_number = tech_pvt->caller_profile->destination_number;
244 	}
245 
246 	if (zstr(callee_name) && !zstr(callee_number)) {
247 		callee_name = callee_number;
248 	}
249 
250 	callee_number = switch_sanitize_number(switch_core_session_strdup(session, callee_number));
251 	callee_name = switch_sanitize_number(switch_core_session_strdup(session, callee_name));
252 
253 	if (!zstr(callee_number) && (zstr(ua) || !switch_stristr("polycom", ua))) {
254 		callee_number = switch_core_session_sprintf(session, "sip:%s@%s", callee_number, host);
255 	}
256 
257 	header = (tech_pvt->cid_type == CID_TYPE_RPID && !switch_stristr("aastra", ua)) ? "Remote-Party-ID" : "P-Asserted-Identity";
258 
259 	if (!zstr(callee_name) && strcmp(callee_name, "_undef_") && !zstr(callee_number)) {
260 		check_decode(callee_name, tech_pvt->session);
261 
262 		if (switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote)) {
263 			pai = switch_core_session_sprintf(tech_pvt->session, "%s: \"%s\" <%s>%s\n"
264 											  "X-FS-Display-Name: %s\nX-FS-Display-Number: %s\n",
265 											  header, callee_name, callee_number,
266 											  tech_pvt->cid_type == CID_TYPE_RPID && !switch_stristr("aastra", ua) ?
267 											  ";party=calling;privacy=off;screen=no" : "",
268 											  callee_name, callee_number);
269 		} else {
270 			pai = switch_core_session_sprintf(tech_pvt->session, "%s: \"%s\" <%s>%s\n", header, callee_name, callee_number,
271 											  tech_pvt->cid_type == CID_TYPE_RPID && !switch_stristr("aastra", ua) ?
272 											  ";party=calling;privacy=off;screen=no" : "");
273 		}
274 
275 	}
276 
277 	return pai;
278 }
279 
sofia_get_jb(switch_core_session_t * session,switch_media_type_t type)280 static switch_jb_t *sofia_get_jb(switch_core_session_t *session, switch_media_type_t type)
281 {
282 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
283 
284 	return switch_core_media_get_jb(tech_pvt->session, type);
285 }
286 
287 /* map QSIG cause codes to SIP from RFC4497 section 8.4.1 */
hangup_cause_to_sip(switch_call_cause_t cause)288 static int hangup_cause_to_sip(switch_call_cause_t cause)
289 {
290 	switch (cause) {
291 	case SWITCH_CAUSE_UNALLOCATED_NUMBER:
292 	case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
293 	case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
294 		return 404;
295 	case SWITCH_CAUSE_USER_BUSY:
296 		return 486;
297 	case SWITCH_CAUSE_NO_USER_RESPONSE:
298 		return 408;
299 	case SWITCH_CAUSE_NO_ANSWER:
300 	case SWITCH_CAUSE_SUBSCRIBER_ABSENT:
301 		return 480;
302 	case SWITCH_CAUSE_CALL_REJECTED:
303 		return 603;
304 	case SWITCH_CAUSE_NUMBER_CHANGED:
305 	case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION:
306 		return 410;
307 	case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
308 	case SWITCH_CAUSE_INVALID_PROFILE:
309 		return 502;
310 	case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
311 	case SWITCH_CAUSE_INVALID_URL:
312 	case SWITCH_CAUSE_INVALID_GATEWAY:
313 		return 484;
314 	case SWITCH_CAUSE_FACILITY_REJECTED:
315 		return 501;
316 	case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
317 		return 480;
318 	case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
319 	case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
320 	case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
321 	case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE:
322 	case SWITCH_CAUSE_SWITCH_CONGESTION:
323 	case SWITCH_CAUSE_GATEWAY_DOWN:
324 		return 503;
325 	case SWITCH_CAUSE_OUTGOING_CALL_BARRED:
326 	case SWITCH_CAUSE_INCOMING_CALL_BARRED:
327 	case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH:
328 		return 403;
329 	case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL:
330 		return 503;
331 	case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL:
332 	case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
333 		return 488;
334 	case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
335 	case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED:
336 		return 501;
337 	case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE:
338 		return 504;
339 	case SWITCH_CAUSE_ORIGINATOR_CANCEL:
340 		return 487;
341 	case SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR:
342 		return 483;
343 	/* Custom mappings not part of RFC */
344 	case SWITCH_CAUSE_BUSY_EVERYWHERE:
345 		return 600;
346 	case SWITCH_CAUSE_DECLINE:
347 		return 603;
348 	case SWITCH_CAUSE_DOES_NOT_EXIST_ANYWHERE:
349 		return 604;
350 	case SWITCH_CAUSE_NOT_ACCEPTABLE:
351 		return 606;
352 	case SWITCH_CAUSE_UNWANTED:
353 		return 607;
354 	default:
355 		return 480;
356 	}
357 }
358 
sofia_on_destroy(switch_core_session_t * session)359 switch_status_t sofia_on_destroy(switch_core_session_t *session)
360 {
361 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
362 	switch_channel_t *channel = switch_core_session_get_channel(session);
363 
364 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SOFIA DESTROY\n", switch_channel_get_name(channel));
365 
366 	if (tech_pvt) {
367 
368 		if (tech_pvt->proxy_refer_msg) {
369 			msg_ref_destroy(tech_pvt->proxy_refer_msg);
370 			tech_pvt->proxy_refer_msg = NULL;
371 		}
372 
373 		if (tech_pvt->respond_phrase) {
374 			switch_yield(100000);
375 		}
376 
377 		if (!zstr(tech_pvt->call_id)) {
378 			switch_core_hash_delete_locked(tech_pvt->profile->chat_hash, tech_pvt->call_id, tech_pvt->profile->flag_mutex);
379 		}
380 
381 
382 		switch_mutex_lock(tech_pvt->profile->flag_mutex);
383 		tech_pvt->profile->inuse--;
384 		switch_mutex_unlock(tech_pvt->profile->flag_mutex);
385 
386 		switch_media_handle_destroy(session);
387 
388 
389 		if (sofia_test_pflag(tech_pvt->profile, PFLAG_DESTROY) && !tech_pvt->profile->inuse) {
390 			sofia_profile_destroy(tech_pvt->profile);
391 		}
392 	}
393 
394 	return SWITCH_STATUS_SUCCESS;
395 
396 }
397 
sofia_on_hangup(switch_core_session_t * session)398 switch_status_t sofia_on_hangup(switch_core_session_t *session)
399 {
400 	switch_core_session_t *a_session;
401 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
402 	switch_channel_t *channel = switch_core_session_get_channel(session);
403 	switch_call_cause_t cause = switch_channel_get_cause(channel);
404 	int sip_cause = hangup_cause_to_sip(cause);
405 	const char *ps_cause = NULL, *use_my_cause;
406 	const char *gateway_name = NULL;
407 	sofia_gateway_t *gateway_ptr = NULL;
408 
409 	if ((gateway_name = switch_channel_get_variable(channel, "sip_gateway_name"))) {
410 		gateway_ptr = sofia_reg_find_gateway(gateway_name);
411 	}
412 
413 	if (!tech_pvt) {
414 		return SWITCH_STATUS_SUCCESS;
415 	}
416 
417 	switch_mutex_lock(tech_pvt->sofia_mutex);
418 
419 
420 	if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
421 		if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
422 			tech_pvt->profile->ob_failed_calls++;
423 		} else {
424 			tech_pvt->profile->ib_failed_calls++;
425 		}
426 
427 		if (gateway_ptr) {
428 			if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
429 				gateway_ptr->ob_failed_calls++;
430 			} else {
431 				gateway_ptr->ib_failed_calls++;
432 			}
433 		}
434 	}
435 
436 	if (gateway_ptr) {
437 		sofia_reg_release_gateway(gateway_ptr);
438 	}
439 
440 	if (!((use_my_cause = switch_channel_get_variable(channel, "sip_ignore_remote_cause")) && switch_true(use_my_cause))) {
441 		ps_cause = switch_channel_get_variable(channel, "last_bridge_" SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE);
442 	}
443 
444 	if (!zstr(ps_cause) && (!strncasecmp(ps_cause, "sip:", 4) || !strncasecmp(ps_cause, "sips:", 5))) {
445 		int new_cause = atoi(sofia_glue_strip_proto(ps_cause));
446 		if (new_cause) {
447 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Overriding SIP cause %d with %d from the other leg\n",
448 							  switch_channel_get_name(channel), sip_cause, new_cause);
449 			sip_cause = new_cause;
450 		}
451 	}
452 
453 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Channel %s hanging up, cause: %s\n",
454 					  switch_channel_get_name(channel), switch_channel_cause2str(cause));
455 
456 	if (tech_pvt->hash_key && !sofia_test_pflag(tech_pvt->profile, PFLAG_DESTROY)) {
457 		switch_core_hash_delete_locked(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt->profile->flag_mutex);
458 	}
459 
460 	if (session && tech_pvt->profile->pres_type) {
461 		char *sql = switch_mprintf("delete from sip_dialogs where uuid='%q'", switch_core_session_get_uuid(session));
462 		switch_assert(sql);
463 		sofia_glue_execute_sql_now(tech_pvt->profile, &sql, SWITCH_TRUE);
464 	}
465 
466 	if (tech_pvt->kick && (a_session = switch_core_session_locate(tech_pvt->kick))) {
467 		switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
468 		switch_channel_hangup(a_channel, switch_channel_get_cause(channel));
469 		switch_core_session_rwunlock(a_session);
470 	}
471 
472 	if (sofia_test_pflag(tech_pvt->profile, PFLAG_DESTROY)) {
473 		sofia_set_flag(tech_pvt, TFLAG_BYE);
474 	} else if (tech_pvt->nh && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
475 		char reason[128] = "";
476 		char *bye_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_BYE_HEADER_PREFIX);
477 		const char *val = NULL;
478 		const char *max_forwards = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE);
479 		const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full");
480 		const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
481 
482 		val = switch_channel_get_variable(tech_pvt->channel, "disable_q850_reason");
483 
484 		if (!val || switch_false(val)) {
485 			if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_reason"))) {
486 				switch_snprintf(reason, sizeof(reason), "%s", val);
487 			} else {
488 				if ((switch_channel_test_flag(channel, CF_INTERCEPT) || cause == SWITCH_CAUSE_PICKED_OFF || cause == SWITCH_CAUSE_LOSE_RACE)
489 					&& !switch_true(switch_channel_get_variable(channel, "ignore_completed_elsewhere"))) {
490 					switch_snprintf(reason, sizeof(reason), "SIP;cause=200;text=\"Call completed elsewhere\"");
491 				} else if (cause > 0 && cause < 128) {
492 					switch_snprintf(reason, sizeof(reason), "Q.850;cause=%d;text=\"%s\"", cause, switch_channel_cause2str(cause));
493 				} else {
494 					switch_snprintf(reason, sizeof(reason), "SIP;cause=%d;text=\"%s\"", cause, switch_channel_cause2str(cause));
495 				}
496 			}
497 		}
498 
499 		if (switch_channel_test_flag(channel, CF_INTERCEPT) || cause == SWITCH_CAUSE_PICKED_OFF || cause == SWITCH_CAUSE_LOSE_RACE) {
500 			switch_channel_set_variable(channel, "call_completed_elsewhere", "true");
501 		}
502 
503 		if (switch_channel_test_flag(channel, CF_ANSWERED) || sofia_test_flag(tech_pvt, TFLAG_ANS)) {
504 			if (!tech_pvt->got_bye) {
505 				switch_channel_set_variable(channel, "sip_hangup_disposition", "send_bye");
506 			}
507 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sending BYE to %s\n", switch_channel_get_name(channel));
508 			if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
509 				nua_bye(tech_pvt->nh,
510 				        TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)),
511 						SIPTAG_CONTACT(SIP_NONE),
512 						TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)),
513 						TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
514 						TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
515 						TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)),
516 						TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
517 						TAG_END());
518 			}
519 		} else {
520 			if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
521 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel));
522 				if (!tech_pvt->got_bye) {
523 					switch_channel_set_variable(channel, "sip_hangup_disposition", "send_cancel");
524 					switch_channel_set_variable(channel, "sip_invite_failure_status", "487");
525 					switch_channel_set_variable(channel, "sip_invite_failure_phrase", "CANCEL");
526 				}
527 				if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
528 					nua_cancel(tech_pvt->nh,
529 							   SIPTAG_CONTACT(SIP_NONE),
530 							   TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
531 							   TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)), TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)),
532 							   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
533 							   TAG_END());
534 				}
535 			} else {
536 				char *resp_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX);
537 				const char *phrase;
538 				char *added_headers = NULL;
539 
540 
541 				if (tech_pvt->respond_phrase) {
542 					//phrase = su_strdup(nua_handle_home(tech_pvt->nh), tech_pvt->respond_phrase);
543 					phrase = tech_pvt->respond_phrase;
544 				} else {
545 					phrase = sip_status_phrase(sip_cause);
546 				}
547 
548 				if (tech_pvt->respond_code) {
549 					sip_cause = tech_pvt->respond_code;
550 					switch (sip_cause) {
551 					case 401:
552 					case 407:
553 						{
554 							const char *to_host = switch_channel_get_variable(channel, "sip_challenge_realm");
555 
556 							if (zstr(to_host)) {
557 								to_host = switch_channel_get_variable(channel, "sip_to_host");
558 							}
559 
560 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Challenging call\n");
561 							sofia_reg_auth_challenge(tech_pvt->profile, tech_pvt->nh, NULL, REG_INVITE, to_host, 0, 0);
562 							*reason = '\0';
563 						}
564 						break;
565 
566 					case 484:
567 						{
568 							const char *to = switch_channel_get_variable(channel, "sip_to_uri");
569 							char *to_uri = NULL;
570 
571 							if (to) {
572 								char *p;
573 								to_uri = switch_core_session_sprintf(session, "sip:%s", to);
574 								if ((p = strstr(to_uri, ":5060"))) {
575 									*p = '\0';
576 								}
577 
578 								tech_pvt->respond_dest = to_uri;
579 
580 							}
581 
582 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Overlap Dial with %d %s\n", sip_cause, phrase);
583 
584 						}
585 						break;
586 
587 					default:
588 						break;
589 
590 					}
591 				}
592 
593 				if (tech_pvt->respond_dest && !sofia_test_pflag(tech_pvt->profile, PFLAG_MANUAL_REDIRECT)) {
594 					added_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
595 				}
596 
597 
598 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Responding to INVITE with: %d\n", sip_cause);
599 				if (!tech_pvt->got_bye) {
600 					switch_channel_set_variable(channel, "sip_hangup_disposition", "send_refuse");
601 				}
602 				if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
603 					char *cid = generate_pai_str(tech_pvt);
604 
605 					if (sip_cause > 299) {
606 						switch_channel_clear_app_flag_key("T38", tech_pvt->channel, CF_APP_T38);
607 						switch_channel_clear_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_REQ);
608 						switch_channel_set_app_flag_key("T38", tech_pvt->channel, CF_APP_T38_FAIL);
609 					}
610 
611 					nua_respond(tech_pvt->nh, sip_cause, phrase,
612 								TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)),
613 								TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
614 								TAG_IF(!zstr(bye_headers), SIPTAG_HEADER_STR(bye_headers)),
615 								TAG_IF(!zstr(resp_headers), SIPTAG_HEADER_STR(resp_headers)),
616 								TAG_IF(!zstr(added_headers), SIPTAG_HEADER_STR(added_headers)),
617 								TAG_IF(tech_pvt->respond_dest, SIPTAG_CONTACT_STR(tech_pvt->respond_dest)),
618 								TAG_IF(!zstr(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)),
619 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
620 								TAG_END());
621 
622 					switch_safe_free(resp_headers);
623 				}
624 				switch_safe_free(added_headers);
625 			}
626 		}
627 		sofia_set_flag_locked(tech_pvt, TFLAG_BYE);
628 		switch_safe_free(bye_headers);
629 	}
630 
631 	if (cause == SWITCH_CAUSE_WRONG_CALL_STATE) {
632 		switch_event_t *s_event;
633 		if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_WRONG_CALL_STATE) == SWITCH_STATUS_SUCCESS) {
634 			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "from_user", tech_pvt->from_user);
635 			switch_event_add_header_string(s_event, SWITCH_STACK_BOTTOM, "network_ip", tech_pvt->mparams.remote_ip);
636 			switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "network_port", "%d", tech_pvt->mparams.remote_port);
637 			switch_event_fire(&s_event);
638 		}
639 	}
640 
641 	sofia_clear_flag(tech_pvt, TFLAG_IO);
642 
643 	if (tech_pvt->sofia_private) {
644 		/* set to NULL so that switch_core_session_locate no longer succeeds, but don't lose the UUID in uuid_str so we
645 		 * can fire events with session UUID */
646 		tech_pvt->sofia_private->uuid = NULL;
647 	}
648 
649 	switch_mutex_unlock(tech_pvt->sofia_mutex);
650 
651 	return SWITCH_STATUS_SUCCESS;
652 }
653 
sofia_on_exchange_media(switch_core_session_t * session)654 static switch_status_t sofia_on_exchange_media(switch_core_session_t *session)
655 {
656 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SOFIA EXCHANGE_MEDIA\n");
657 	return SWITCH_STATUS_SUCCESS;
658 }
659 
sofia_on_soft_execute(switch_core_session_t * session)660 static switch_status_t sofia_on_soft_execute(switch_core_session_t *session)
661 {
662 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SOFIA SOFT_EXECUTE\n");
663 	return SWITCH_STATUS_SUCCESS;
664 }
665 
sofia_acknowledge_call(switch_core_session_t * session)666 static switch_status_t sofia_acknowledge_call(switch_core_session_t *session)
667 {
668 	struct private_object *tech_pvt = switch_core_session_get_private(session);
669 	const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
670 
671 	if (!tech_pvt->sent_100) {
672 		nua_respond(tech_pvt->nh, SIP_100_TRYING, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END());
673 		tech_pvt->sent_100 = 1;
674 		return SWITCH_STATUS_SUCCESS;
675 	}
676 
677 	return SWITCH_STATUS_FALSE;
678 }
679 
sofia_answer_channel(switch_core_session_t * session)680 static switch_status_t sofia_answer_channel(switch_core_session_t *session)
681 {
682 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
683 	switch_channel_t *channel = switch_core_session_get_channel(session);
684 	switch_status_t status;
685 	uint32_t session_timeout = tech_pvt->profile->session_timeout;
686 	const char *val;
687 	const char *b_sdp = NULL;
688 	int is_proxy = 0;
689 	int is_3pcc_proxy = 0;
690 	int is_3pcc = 0;
691 	char *sticky = NULL;
692 	const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full");
693 	const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
694 
695 	if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) {
696 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying");
697 	}
698 
699 	if (switch_channel_test_flag(channel, CF_CONFERENCE) && !zstr(tech_pvt->reply_contact) && !switch_stristr(";isfocus", tech_pvt->reply_contact)) {
700 		tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;isfocus", tech_pvt->reply_contact);
701 	}
702 
703 	//switch_core_media_set_local_sdp
704 	if(sofia_test_flag(tech_pvt, TFLAG_3PCC_INVITE)) {
705 		// SNARK: complete hack to get final ack sent when a 3pcc invite has been passed from the other leg in bypass_media mode.
706 			// This code handles the pass_indication sent after the 3pcc ack is received by the other leg in the is_3pcc && is_proxy case below.
707 	 	// Is there a better place to hang this...?
708 		b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE);
709 		switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE);
710 
711 		if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA)) {
712 			sofia_media_activate_rtp(tech_pvt);
713 			switch_core_media_patch_sdp(tech_pvt->session);
714 			switch_core_media_proxy_remote_addr(tech_pvt->session, NULL);
715 		}
716 
717 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
718 						  "3PCC-PROXY nomedia - sending ack, SDP:\n%s\n", tech_pvt->mparams.local_sdp_str);
719 
720 
721 		if (sofia_use_soa(tech_pvt)) {
722 			nua_ack(tech_pvt->nh,
723 					TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
724 					SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
725 					SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
726 					SOATAG_REUSE_REJECTED(1),
727 					SOATAG_RTP_SELECT(1),
728 					SOATAG_AUDIO_AUX("cn telephone-event"),
729 					TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
730 					TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
731 					TAG_END());
732 		} else {
733 			nua_ack(tech_pvt->nh,
734 					NUTAG_MEDIA_ENABLE(0),
735 					TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
736 					SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
737 					TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
738 					TAG_IF(tech_pvt->mparams.local_sdp_str, SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str)),
739 					TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
740 					SOATAG_AUDIO_AUX("cn telephone-event"),
741 					TAG_END());
742 		}
743 
744 
745 		sofia_clear_flag(tech_pvt, TFLAG_3PCC_INVITE); // all done
746 		sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
747 		sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
748 		switch_channel_mark_answered(channel);     // ... and remember to actually answer the call!
749 		return SWITCH_STATUS_SUCCESS;
750 	}
751 
752 	if (sofia_test_flag(tech_pvt, TFLAG_ANS) || switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
753 		return SWITCH_STATUS_SUCCESS;
754 	}
755 
756 	b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE);
757 	is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA));
758 	is_3pcc_proxy = (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC));
759 	is_3pcc = (!sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC));
760 
761 	if (b_sdp && is_proxy && !is_3pcc_proxy) {
762 		switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE);
763 
764 		if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
765 			switch_core_media_patch_sdp(tech_pvt->session);
766 			if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
767 				return SWITCH_STATUS_FALSE;
768 			}
769 		}
770 	} else {
771 		/* This if statement check and handles the 3pcc proxy mode */
772 
773 		if (is_3pcc) {
774 			switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
775 			tech_pvt->mparams.local_sdp_str = NULL;
776 			switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0);
777 			switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
778 		} else if (is_3pcc_proxy) {
779 
780 			if (!(sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY))) {
781 				switch_channel_set_flag(channel, CF_3PCC);
782 			}
783 
784 			if (b_sdp && is_proxy && !switch_channel_var_true(channel, "3pcc_always_gen_sdp")) {
785 				switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE);
786 			} else {
787 				switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0);
788 				switch_core_media_prepare_codecs(session, 1);
789 				switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 1);
790 				sofia_set_flag_locked(tech_pvt, TFLAG_3PCC);
791 			}
792 
793 			if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
794 				switch_core_media_patch_sdp(tech_pvt->session);
795 				if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
796 					return SWITCH_STATUS_FALSE;
797 				}
798 			}
799 		}
800 
801 		if (is_3pcc || is_3pcc_proxy) {
802 			/* Send the 200 OK */
803 			if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
804 				char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX);
805 
806 				if (sofia_use_soa(tech_pvt)) {
807 
808 					nua_respond(tech_pvt->nh, SIP_200_OK,
809 								TAG_IF(is_proxy, NUTAG_AUTOANSWER(0)),
810 								SIPTAG_CONTACT_STR(tech_pvt->profile->url),
811 								SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
812 								TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
813 								SOATAG_REUSE_REJECTED(1),
814 								SOATAG_RTP_SELECT(1),
815 								SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1),
816 								TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
817 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
818 								TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
819 									   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());
820 				} else {
821 					nua_respond(tech_pvt->nh, SIP_200_OK,
822 								NUTAG_MEDIA_ENABLE(0),
823 								SIPTAG_CONTACT_STR(tech_pvt->profile->url),
824 								TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
825 								TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
826 								SIPTAG_CONTENT_TYPE_STR("application/sdp"),
827 								SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str),
828 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
829 								TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
830 									   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());
831 				}
832 
833 
834 				switch_safe_free(extra_headers);
835 			}
836 
837 			if (is_3pcc_proxy) {
838 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Sent a 200 OK, waiting for ACK\n");
839 				/* Unlock the session signal to allow the ack to make it in */
840 				// Maybe we should timeout?
841 				switch_mutex_unlock(tech_pvt->sofia_mutex);
842 
843 				while (switch_channel_ready(channel) && !sofia_test_flag(tech_pvt, TFLAG_3PCC_HAS_ACK)) {
844 					switch_cond_next();
845 				}
846 
847 				/*  Regain lock on sofia */
848 				switch_mutex_lock(tech_pvt->sofia_mutex);
849 
850 				if (is_proxy) {
851 					sofia_clear_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
852 					sofia_clear_flag(tech_pvt, TFLAG_3PCC);
853 					switch_core_session_pass_indication(session, SWITCH_MESSAGE_INDICATE_ANSWER);
854 				}
855 
856 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Done waiting for ACK\n");
857 				return SWITCH_STATUS_SUCCESS;
858 			}
859 		}
860 
861 		if ((is_proxy && !b_sdp) || sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) ||
862 			switch_core_media_codec_chosen(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO) != SWITCH_STATUS_SUCCESS) {
863 			sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
864 
865 			if (is_proxy) {
866 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Disabling proxy mode due to call answer with no bridge\n");
867 				switch_channel_clear_flag(channel, CF_PROXY_MEDIA);
868 				switch_channel_clear_flag(channel, CF_PROXY_MODE);
869 			}
870 
871 			if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
872 				const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
873 
874 				switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
875 
876 				if (zstr(r_sdp) || sofia_media_tech_media(tech_pvt, r_sdp, SDP_TYPE_REQUEST) != SWITCH_STATUS_SUCCESS) {
877 					switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
878 					//switch_mutex_lock(tech_pvt->sofia_mutex);
879 					//nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
880 					//switch_mutex_unlock(tech_pvt->sofia_mutex);
881 					return SWITCH_STATUS_FALSE;
882 				}
883 			}
884 		}
885 
886 		if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) {
887 			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
888 			return status;
889 		}
890 
891 		switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
892 		if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
893 			switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
894 		}
895 
896 		if (tech_pvt->nh) {
897 			if (tech_pvt->mparams.local_sdp_str) {
898 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n", switch_channel_get_name(channel),
899 								  tech_pvt->mparams.local_sdp_str);
900 			}
901 		}
902 
903 	}
904 
905 	if (sofia_test_flag(tech_pvt, TFLAG_NAT) ||
906 		(val = switch_channel_get_variable(channel, "sip-force-contact")) ||
907 		((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val))) {
908 		sticky = tech_pvt->record_route;
909 		session_timeout = SOFIA_NAT_SESSION_TIMEOUT;
910 		switch_channel_set_variable(channel, "sip_nat_detected", "true");
911 	}
912 
913 	if ((val = switch_channel_get_variable(channel, SOFIA_SESSION_TIMEOUT))) {
914 		int v_session_timeout = atoi(val);
915 		if (v_session_timeout >= 0) {
916 			session_timeout = v_session_timeout;
917 		}
918 	}
919 
920 	if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
921 		char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX);
922 		char *cid = NULL;
923 
924 
925 		cid = generate_pai_str(tech_pvt);
926 
927 
928 		if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->mparams.early_sdp && tech_pvt->mparams.local_sdp_str) {
929 			char *a, *b;
930 
931 			/* start at the s= line to avoid some devices who update the o= between messages */
932 			a = strstr(tech_pvt->mparams.early_sdp, "s=");
933 			b = strstr(tech_pvt->mparams.local_sdp_str, "s=");
934 
935 			if (!a || !b || strcmp(a, b)) {
936 
937 				/* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless
938 				   we do so in this case we will abandon the SOA rules and go rogue.
939 				*/
940 				sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
941 			}
942 		}
943 
944 		if ((tech_pvt->mparams.last_sdp_str && strstr(tech_pvt->mparams.last_sdp_str, "a=setup")) ||
945 			(tech_pvt->mparams.local_sdp_str && strstr(tech_pvt->mparams.local_sdp_str, "a=setup"))) {
946 			session_timeout = 0;
947 		}
948 
949 		if ((tech_pvt->session_timeout = session_timeout)) {
950 			tech_pvt->session_refresher = switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? nua_local_refresher : nua_remote_refresher;
951 			if (sofia_test_pflag(tech_pvt->profile, PFLAG_UPDATE_REFRESHER) || switch_channel_var_true(tech_pvt->channel, "sip_update_refresher")) {
952 				tech_pvt->update_refresher = 1;
953 			}
954 		} else {
955 			tech_pvt->session_refresher = nua_no_refresher;
956 		}
957 
958 		if (sofia_use_soa(tech_pvt)) {
959 			nua_respond(tech_pvt->nh, SIP_200_OK,
960 						NUTAG_AUTOANSWER(0),
961 						TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
962 						TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
963 						TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
964 						TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
965 						NUTAG_SESSION_TIMER(tech_pvt->session_timeout),
966 						NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher),
967 						NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher),
968 						SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
969 						SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
970 						SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
971 						SOATAG_REUSE_REJECTED(1),
972 						SOATAG_AUDIO_AUX("cn telephone-event"),
973 						TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
974 						SOATAG_RTP_SELECT(1),
975 						TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
976 						TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
977 							   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());
978 		} else {
979 			nua_respond(tech_pvt->nh, SIP_200_OK,
980 						NUTAG_AUTOANSWER(0),
981 						NUTAG_MEDIA_ENABLE(0),
982 						TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
983 						TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
984 						TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
985 						TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
986 						NUTAG_SESSION_TIMER(tech_pvt->session_timeout),
987 						NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher),
988 						NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher),
989 						SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
990 						SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
991 						SIPTAG_CONTENT_TYPE_STR("application/sdp"),
992 						SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str),
993 						TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
994 						TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
995 							   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());
996 		}
997 		switch_safe_free(extra_headers);
998 		sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
999 	}
1000 
1001 	return SWITCH_STATUS_SUCCESS;
1002 }
1003 
sofia_read_text_frame(switch_core_session_t * session,switch_frame_t ** frame,switch_io_flag_t flags,int stream_id)1004 static switch_status_t sofia_read_text_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
1005 {
1006 	switch_status_t status;
1007 
1008 	if (switch_channel_test_flag(switch_core_session_get_channel(session), CF_MSRP)) {
1009 		switch_msrp_session_t *msrp_session = switch_core_media_get_msrp_session(session);
1010 		switch_frame_t *rframe = &msrp_session->frame;
1011 		switch_msrp_msg_t *msrp_msg = switch_msrp_session_pop_msg(msrp_session);
1012 		const char *msrp_h_content_type = NULL;
1013 
1014 		if (msrp_msg) {
1015 			msrp_h_content_type = switch_msrp_msg_get_header(msrp_msg, MSRP_H_CONTENT_TYPE);
1016 		}
1017 
1018 		rframe->flags = 0;
1019 		rframe->data = msrp_session->frame_data;
1020 		rframe->buflen = sizeof(msrp_session->frame_data);
1021 
1022 		if (msrp_msg && msrp_msg->method == MSRP_METHOD_SEND &&
1023 			msrp_msg->payload &&
1024 			!switch_stristr("?OTRv3?", msrp_msg->payload) &&
1025 			!switch_stristr("application/im-iscomposing", msrp_msg->payload) &&
1026 			msrp_h_content_type &&
1027 			(switch_stristr("text/plain", msrp_h_content_type) ||
1028 			 switch_stristr("text/html", msrp_h_content_type) ||
1029 			 switch_stristr("message/cpim", msrp_h_content_type))) {
1030 
1031 			rframe->datalen = msrp_msg->payload_bytes;
1032 			rframe->packetlen = msrp_msg->payload_bytes + 12;
1033 			memcpy(rframe->data, msrp_msg->payload, msrp_msg->payload_bytes + 1); /* include the last NULL byte */
1034 
1035 			rframe->m = 1;
1036 			*frame = rframe;
1037 
1038 			if (!strcasecmp(msrp_h_content_type, "message/cpim")) {
1039 				char *stripped_text = switch_html_strip((char *)rframe->data);
1040 				memcpy(rframe->data, stripped_text, strlen(stripped_text)+1);
1041 				rframe->datalen = strlen(stripped_text);
1042 				free(stripped_text);
1043 			}
1044 
1045 			switch_msrp_msg_destroy(&msrp_msg);
1046 			status = SWITCH_STATUS_SUCCESS;
1047 		} else {
1048 			rframe->datalen = 2;
1049 			rframe->flags = SFF_CNG;
1050 			*frame = rframe;
1051 			status = SWITCH_STATUS_SUCCESS;
1052 		}
1053 
1054 		return status;
1055 	}
1056 
1057 	return switch_core_media_read_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_TEXT);
1058 }
1059 
sofia_write_text_frame(switch_core_session_t * session,switch_frame_t * frame,switch_io_flag_t flags,int stream_id)1060 static switch_status_t sofia_write_text_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
1061 {
1062 	if (switch_channel_test_flag(switch_core_session_get_channel(session), CF_MSRP)) {
1063 		switch_msrp_session_t *msrp_session = switch_core_media_get_msrp_session(session);
1064 
1065 		if (frame && msrp_session) {
1066 			switch_msrp_msg_t *msrp_msg = switch_msrp_msg_create();
1067 			switch_status_t status = SWITCH_STATUS_SUCCESS;
1068 
1069 			// switch_msrp_msg_add_header(&msrp_msg, MSRP_H_CONTENT_TYPE, "message/cpim");
1070 			switch_msrp_msg_add_header(msrp_msg, MSRP_H_CONTENT_TYPE, "text/plain");
1071 			switch_msrp_msg_set_payload(msrp_msg, frame->data, frame->datalen);
1072 			status = switch_msrp_send(msrp_session, msrp_msg);
1073 			switch_msrp_msg_destroy(&msrp_msg);
1074 			return status;
1075 		}
1076 
1077 		return SWITCH_STATUS_FALSE;
1078 	}
1079 
1080 	return switch_core_media_write_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_TEXT);
1081 }
1082 
sofia_read_video_frame(switch_core_session_t * session,switch_frame_t ** frame,switch_io_flag_t flags,int stream_id)1083 static switch_status_t sofia_read_video_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
1084 {
1085 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
1086 
1087 	switch_assert(tech_pvt != NULL);
1088 
1089 	if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
1090 		return SWITCH_STATUS_FALSE;
1091 	}
1092 #if 0
1093 	while (!(tech_pvt->video_read_codec.implementation && switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO) && !switch_channel_test_flag(channel, CF_REQ_MEDIA))) {
1094 		switch_ivr_parse_all_messages(tech_pvt->session);
1095 
1096 		if (--sanity && switch_channel_ready(channel)) {
1097 			switch_yield(10000);
1098 		} else {
1099 			switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE);
1100 			return SWITCH_STATUS_GENERR;
1101 		}
1102 	}
1103 #endif
1104 
1105 
1106 	return switch_core_media_read_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_VIDEO);
1107 
1108 }
1109 
sofia_write_video_frame(switch_core_session_t * session,switch_frame_t * frame,switch_io_flag_t flags,int stream_id)1110 static switch_status_t sofia_write_video_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
1111 {
1112 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_get_private(session);
1113 	switch_assert(tech_pvt != NULL);
1114 
1115 #if 0
1116 	while (!(tech_pvt->video_read_codec.implementation && switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO))) {
1117 		if (switch_channel_ready(channel)) {
1118 			switch_yield(10000);
1119 		} else {
1120 			return SWITCH_STATUS_GENERR;
1121 		}
1122 	}
1123 #endif
1124 
1125 	if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
1126 		return SWITCH_STATUS_FALSE;
1127 	}
1128 
1129 	if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
1130 		return SWITCH_STATUS_GENERR;
1131 	}
1132 
1133 	if (!sofia_test_flag(tech_pvt, TFLAG_IO)) {
1134 		return SWITCH_STATUS_SUCCESS;
1135 	}
1136 
1137 	if (SWITCH_STATUS_SUCCESS == switch_core_media_write_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_VIDEO)) {
1138 		return SWITCH_STATUS_SUCCESS;
1139 	}
1140 
1141 	return SWITCH_STATUS_FALSE;
1142 }
1143 
sofia_read_frame(switch_core_session_t * session,switch_frame_t ** frame,switch_io_flag_t flags,int stream_id)1144 static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
1145 {
1146 	private_object_t *tech_pvt = switch_core_session_get_private(session);
1147 	switch_status_t status = SWITCH_STATUS_FALSE;
1148 
1149 	switch_assert(tech_pvt != NULL);
1150 
1151 	if (!sofia_test_pflag(tech_pvt->profile, PFLAG_RUNNING)) {
1152 		switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_NORMAL_CLEARING);
1153 		return SWITCH_STATUS_FALSE;
1154 	}
1155 
1156 	if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
1157 		return SWITCH_STATUS_FALSE;
1158 	}
1159 
1160 	if (!(switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO))){
1161 		return SWITCH_STATUS_INUSE;
1162 	}
1163 
1164 	sofia_set_flag_locked(tech_pvt, TFLAG_READING);
1165 
1166 	if (sofia_test_flag(tech_pvt, TFLAG_HUP) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
1167 		return SWITCH_STATUS_FALSE;
1168 	}
1169 
1170 	status = switch_core_media_read_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_AUDIO);
1171 
1172 	sofia_clear_flag_locked(tech_pvt, TFLAG_READING);
1173 
1174 	return status;
1175 }
1176 
sofia_write_frame(switch_core_session_t * session,switch_frame_t * frame,switch_io_flag_t flags,int stream_id)1177 static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
1178 {
1179 	private_object_t *tech_pvt = switch_core_session_get_private(session);
1180 	switch_channel_t *channel = switch_core_session_get_channel(session);
1181 	switch_status_t status = SWITCH_STATUS_SUCCESS;
1182 
1183 	switch_assert(tech_pvt != NULL);
1184 
1185 
1186 	if (!switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
1187 		if (switch_channel_up_nosig(channel)) {
1188 			return SWITCH_STATUS_SUCCESS;
1189 		} else {
1190 			return SWITCH_STATUS_GENERR;
1191 		}
1192 	}
1193 
1194 	if (switch_channel_test_flag(channel, CF_REQ_MEDIA)) {
1195 		if (++tech_pvt->req_media_counter > 2000) {
1196 			switch_channel_clear_flag(channel, CF_REQ_MEDIA);
1197 			switch_channel_hangup(channel, SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE);
1198 			return SWITCH_STATUS_FALSE;
1199 		} else {
1200 			return SWITCH_STATUS_SUCCESS;
1201 		}
1202 	} else {
1203 		tech_pvt->req_media_counter = 0;
1204 	}
1205 
1206 	if (sofia_test_flag(tech_pvt, TFLAG_HUP)) {
1207 		return SWITCH_STATUS_FALSE;
1208 	}
1209 
1210 #if 0
1211 	if (!sofia_test_flag(tech_pvt, TFLAG_RTP)) {
1212 		return SWITCH_STATUS_GENERR;
1213 	}
1214 
1215 	if (!sofia_test_flag(tech_pvt, TFLAG_IO)) {
1216 		return SWITCH_STATUS_SUCCESS;
1217 	}
1218 #endif
1219 
1220 	if (sofia_test_flag(tech_pvt, TFLAG_BYE)) {
1221 		return SWITCH_STATUS_FALSE;
1222 	}
1223 
1224 	sofia_set_flag_locked(tech_pvt, TFLAG_WRITING);
1225 
1226 	if (switch_core_media_write_frame(session, frame, flags, stream_id, SWITCH_MEDIA_TYPE_AUDIO)) {
1227 		status = SWITCH_STATUS_SUCCESS;
1228 	}
1229 
1230 	sofia_clear_flag_locked(tech_pvt, TFLAG_WRITING);
1231 	return status;
1232 }
1233 
sofia_kill_channel(switch_core_session_t * session,int sig)1234 static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig)
1235 {
1236 	private_object_t *tech_pvt = switch_core_session_get_private(session);
1237 
1238 	if (!tech_pvt) {
1239 		return SWITCH_STATUS_FALSE;
1240 	}
1241 
1242 	switch (sig) {
1243 	case SWITCH_SIG_BREAK:
1244 		if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
1245 			switch_core_media_break(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
1246 		}
1247 		if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO)) {
1248 			switch_core_media_break(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO);
1249 		}
1250 		break;
1251 	case SWITCH_SIG_KILL:
1252 	default:
1253 		sofia_clear_flag_locked(tech_pvt, TFLAG_IO);
1254 		sofia_set_flag_locked(tech_pvt, TFLAG_HUP);
1255 
1256 		if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
1257 			switch_core_media_kill_socket(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
1258 		}
1259 		if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO)) {
1260 			switch_core_media_kill_socket(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO);
1261 		}
1262 		break;
1263 	}
1264 	return SWITCH_STATUS_SUCCESS;
1265 }
1266 
1267 
sofia_send_dtmf(switch_core_session_t * session,const switch_dtmf_t * dtmf)1268 static switch_status_t sofia_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
1269 {
1270 	private_object_t *tech_pvt;
1271 	char message[128] = "";
1272 	switch_core_media_dtmf_t dtmf_type;
1273 
1274 	tech_pvt = (private_object_t *) switch_core_session_get_private(session);
1275 	switch_assert(tech_pvt != NULL);
1276 
1277 	switch_core_media_check_dtmf_type(session);
1278 
1279 	dtmf_type = tech_pvt->mparams.dtmf_type;
1280 
1281 	/* We only can send INFO when we have no media */
1282 	if (!switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO) ||
1283 		!switch_channel_media_ready(tech_pvt->channel) || switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) {
1284 		dtmf_type = DTMF_INFO;
1285 	}
1286 
1287 	switch (dtmf_type) {
1288 	case DTMF_2833:
1289 		{
1290 			return switch_core_media_queue_rfc2833(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, dtmf);
1291 		}
1292 	case DTMF_INFO:
1293 		{
1294 			if (dtmf->digit == 'w') {
1295 				switch_yield(500000);
1296 			} else if (dtmf->digit == 'W') {
1297 				switch_yield(1000000);
1298 			} else {
1299 				snprintf(message, sizeof(message), "Signal=%c\r\nDuration=%d\r\n", dtmf->digit, dtmf->duration / 8);
1300 				switch_mutex_lock(tech_pvt->sofia_mutex);
1301 				nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/dtmf-relay"), SIPTAG_PAYLOAD_STR(message), TAG_END());
1302 				switch_mutex_unlock(tech_pvt->sofia_mutex);
1303 			}
1304 		}
1305 		break;
1306 	case DTMF_NONE:
1307 		break;
1308 	default:
1309 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Unhandled DTMF type!\n");
1310 		break;
1311 	}
1312 
1313 	return SWITCH_STATUS_SUCCESS;
1314 }
1315 
sofia_receive_message(switch_core_session_t * session,switch_core_session_message_t * msg)1316 static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
1317 {
1318 	switch_channel_t *channel = switch_core_session_get_channel(session);
1319 	private_object_t *tech_pvt = switch_core_session_get_private(session);
1320 	switch_status_t status = SWITCH_STATUS_SUCCESS;
1321 
1322 	switch_assert(tech_pvt != NULL);
1323 
1324 	if (msg->message_id == SWITCH_MESSAGE_INDICATE_SIGNAL_DATA) {
1325 		sofia_dispatch_event_t *de = (sofia_dispatch_event_t *) msg->pointer_arg;
1326 		switch_mutex_lock(tech_pvt->sofia_mutex);
1327 		if (switch_core_session_in_thread(session)) {
1328 			de->session = session;
1329 		}
1330 
1331 		sofia_process_dispatch_event(&de);
1332 
1333 
1334 		switch_mutex_unlock(tech_pvt->sofia_mutex);
1335 		goto end;
1336 	}
1337 
1338 
1339 	if (switch_channel_down(channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
1340 		status = SWITCH_STATUS_FALSE;
1341 		goto end;
1342 	}
1343 
1344 	if (switch_channel_test_flag(channel, CF_CONFERENCE) && !zstr(tech_pvt->reply_contact) && !switch_stristr(";isfocus", tech_pvt->reply_contact)) {
1345 		tech_pvt->reply_contact = switch_core_session_sprintf(session, "%s;isfocus", tech_pvt->reply_contact);
1346 	}
1347 
1348 	/* ones that do not need to lock sofia mutex */
1349 	switch (msg->message_id) {
1350 	case SWITCH_MESSAGE_INDICATE_KEEPALIVE:
1351 		{
1352 			if (msg->numeric_arg) {
1353 				sofia_set_flag_locked(tech_pvt, TFLAG_KEEPALIVE);
1354 			} else {
1355 				sofia_clear_flag_locked(tech_pvt, TFLAG_KEEPALIVE);
1356 			}
1357 		}
1358 		break;
1359 	case SWITCH_MESSAGE_HEARTBEAT_EVENT:
1360 		{
1361 			char pl[160] = "";
1362 
1363 			switch_snprintf(pl, sizeof(pl), "KEEP-ALIVE %d\n", ++tech_pvt->keepalive);
1364 
1365 			if (sofia_test_flag(tech_pvt, TFLAG_KEEPALIVE)) {
1366 				if (tech_pvt->profile->keepalive == KA_MESSAGE) {
1367 					nua_message(tech_pvt->nh,
1368 								SIPTAG_CONTENT_TYPE_STR("text/plain"),
1369 								TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
1370 								SIPTAG_PAYLOAD_STR(pl),
1371 								TAG_END());
1372 				} else if (tech_pvt->profile->keepalive == KA_INFO) {
1373 					nua_info(tech_pvt->nh,
1374 							 SIPTAG_CONTENT_TYPE_STR("text/plain"),
1375 							 TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
1376 							 SIPTAG_PAYLOAD_STR(pl),
1377 							 TAG_END());
1378 				}
1379 			}
1380 		}
1381 		break;
1382 	case SWITCH_MESSAGE_INDICATE_RECOVERY_REFRESH:
1383 	case SWITCH_MESSAGE_INDICATE_APPLICATION_EXEC:
1384 		break;
1385 	case SWITCH_MESSAGE_INDICATE_MEDIA_RENEG:
1386 		{
1387 			if (msg->string_arg) {
1388 				sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
1389 			}
1390 
1391 			sofia_glue_do_invite(session);
1392 		}
1393 		break;
1394 	case SWITCH_MESSAGE_INDICATE_BRIDGE:
1395 			switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, NULL);
1396 
1397 			if (switch_true(switch_channel_get_variable(channel, "sip_auto_simplify"))) {
1398 				sofia_set_flag(tech_pvt, TFLAG_SIMPLIFY);
1399 			}
1400 
1401 
1402 		break;
1403 	case SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE:
1404 		{
1405 			const char *event;
1406 			const char *uuid;
1407 			char *xdest;
1408 
1409 			if (msg->string_arg) {
1410 				const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1411 				nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
1412 						   NUTAG_SUBSTATE(nua_substate_terminated),
1413 						   SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
1414 						   SIPTAG_PAYLOAD_STR(msg->string_arg),
1415 						   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1416 						   SIPTAG_EVENT_STR("refer"), TAG_END());
1417 				goto end;
1418 			}
1419 
1420 			event = switch_channel_get_variable(channel, "sip_blind_transfer_event");
1421 			uuid = switch_channel_get_variable(channel, "blind_transfer_uuid");
1422 
1423 			if (event && uuid) {
1424 				char payload_str[255] = "SIP/2.0 403 Forbidden\r\n";
1425 				const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1426 				if (msg->numeric_arg) {
1427 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
1428 							"%s Completing blind transfer with success\n", switch_channel_get_name(channel));
1429 					switch_set_string(payload_str, "SIP/2.0 200 OK\r\n");
1430 				} else if (uuid) {
1431 					switch_core_session_t *other_session = switch_core_session_locate(uuid);
1432 					if (other_session) {
1433 						switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
1434 						const char *invite_failure_status = switch_channel_get_variable(other_channel, "sip_invite_failure_status");
1435 						const char *invite_failure_str = switch_channel_get_variable(other_channel, "sip_invite_failure_status");
1436 						if (!zstr(invite_failure_status) && !zstr(invite_failure_str)) {
1437 							snprintf(payload_str, sizeof(payload_str), "SIP/2.0 %s %s\r\n", invite_failure_status, invite_failure_str);
1438 							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
1439 									"%s Completing blind transfer with custom failure: %s %s\n",
1440 									switch_channel_get_name(channel), invite_failure_status, invite_failure_str);
1441 						}
1442 						switch_core_session_rwunlock(other_session);
1443 					}
1444 				}
1445 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
1446 						"%s Completing blind transfer with status: %s\n", switch_channel_get_name(channel), payload_str);
1447 				nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR("message/sipfrag;version=2.0"),
1448 						   NUTAG_SUBSTATE(nua_substate_terminated),
1449 						   SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
1450 						   SIPTAG_PAYLOAD_STR(payload_str),
1451 						   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1452 						   SIPTAG_EVENT_STR(event), TAG_END());
1453 
1454 
1455 				if (!msg->numeric_arg) {
1456 					xdest = switch_core_session_sprintf(session, "intercept:%s", uuid);
1457 					switch_ivr_session_transfer(session, xdest, "inline", NULL);
1458 				}
1459 			}
1460 
1461 		}
1462 		goto end;
1463 	case SWITCH_MESSAGE_INDICATE_CLEAR_PROGRESS:
1464 		if (!switch_channel_test_flag(channel, CF_ANSWERED)) {
1465 			sofia_clear_flag(tech_pvt, TFLAG_EARLY_MEDIA);
1466 		}
1467 		goto end;
1468 	case SWITCH_MESSAGE_INDICATE_ANSWER:
1469 	case SWITCH_MESSAGE_INDICATE_PROGRESS:
1470 		{
1471 			const char *var;
1472 			const char *presence_data = switch_channel_get_variable(channel, "presence_data");
1473 			const char *presence_id = switch_channel_get_variable(channel, "presence_id");
1474 
1475 
1476 			if ((var = switch_channel_get_variable(channel, "sip_force_nat_mode")) && switch_true(var)) {
1477 				sofia_set_flag(tech_pvt, TFLAG_NAT);
1478 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting NAT mode based on manual variable\n");
1479 				switch_channel_set_variable(channel, "sip_nat_detected", "true");
1480 			}
1481 
1482 			if ((var = switch_channel_get_variable(channel, "sip_enable_soa"))) {
1483 				if (switch_true(var)) {
1484 					sofia_set_flag(tech_pvt, TFLAG_ENABLE_SOA);
1485 				} else {
1486 					sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
1487 				}
1488 			}
1489 
1490 
1491 			if (presence_id || presence_data) {
1492 				char *sql = switch_mprintf("update sip_dialogs set presence_id='%q',presence_data='%q' "
1493 										   "where uuid='%q';\n", switch_str_nil(presence_id), switch_str_nil(presence_data),
1494 										   switch_core_session_get_uuid(session));
1495 				switch_assert(sql);
1496 				sofia_glue_execute_sql_now(tech_pvt->profile, &sql, SWITCH_TRUE);
1497 			}
1498 
1499 			if (sofia_test_media_flag(tech_pvt->profile, SCMF_AUTOFIX_TIMING)) {
1500 				switch_core_media_reset_autofix(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
1501 			}
1502 		}
1503 		break;
1504 	default:
1505 		break;
1506 	}
1507 
1508 	/* ones that do need to lock sofia mutex */
1509 	switch_mutex_lock(tech_pvt->sofia_mutex);
1510 
1511 	if (switch_channel_down(channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
1512 		status = SWITCH_STATUS_FALSE;
1513 		goto end_lock;
1514 	}
1515 
1516 	switch (msg->message_id) {
1517 
1518 	case SWITCH_MESSAGE_INDICATE_DEFLECT: {
1519 
1520 		char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
1521 		char ref_to[1024] = "";
1522 		const char *var;
1523 		const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1524 
1525 		if (!strcasecmp(msg->string_arg, "sip:")) {
1526 			const char *format = strchr(tech_pvt->profile->sipip, ':') ? "sip:%s@[%s]" : "sip:%s@%s";
1527 
1528 			switch_snprintf(ref_to, sizeof(ref_to), format, msg->string_arg, tech_pvt->profile->sipip);
1529 		} else {
1530 			switch_set_string(ref_to, msg->string_arg);
1531 		}
1532 
1533 		nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(tech_pvt->contact_url),
1534 				  TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
1535 				  TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1536 				  TAG_END());
1537 
1538 		if (msg->string_array_arg[0]) {
1539 			tech_pvt->proxy_refer_uuid = (char *)msg->string_array_arg[0];
1540 		} else {
1541 			switch_mutex_unlock(tech_pvt->sofia_mutex);
1542 			sofia_wait_for_reply(tech_pvt, 9999, 10);
1543 			switch_mutex_lock(tech_pvt->sofia_mutex);
1544 
1545 			if ((var = switch_channel_get_variable(tech_pvt->channel, "sip_refer_reply"))) {
1546 				msg->string_reply = switch_core_session_strdup(session, var);
1547 			} else {
1548 				msg->string_reply = "no reply";
1549 			}
1550 
1551 			switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BLIND_TRANSFER);
1552 		}
1553 
1554 		switch_safe_free(extra_headers);
1555 	}
1556 		break;
1557 
1558 	case SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ:
1559 		if (switch_channel_media_up(channel) && !switch_channel_test_flag(channel, CF_AVPF) && !switch_channel_test_flag(channel, CF_MANUAL_VID_REFRESH) &&
1560 			switch_channel_var_true(channel, "sofia_send_info_vid_refresh")) {
1561 			const char *pl = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<media_control><vc_primitive><to_encoder><picture_fast_update /></to_encoder></vc_primitive></media_control>\n";
1562 			switch_time_t now = switch_micro_time_now();
1563 
1564 			if (!tech_pvt->last_vid_info || (now - tech_pvt->last_vid_info) > 500000) {
1565 
1566 				tech_pvt->last_vid_info = now;
1567 
1568 				if (!zstr(msg->string_arg)) {
1569 					pl = msg->string_arg;
1570 				}
1571 
1572 				nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("application/media_control+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END());
1573 			}
1574 
1575 		}
1576 		break;
1577 	case SWITCH_MESSAGE_INDICATE_BROADCAST:
1578 		{
1579 			const char *ip = NULL, *port = NULL;
1580 			ip = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
1581 			port = switch_channel_get_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
1582 			if (ip && port) {
1583 				switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, ip, (switch_port_t)atoi(port), msg->string_arg, 1);
1584 			}
1585 
1586 			if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
1587 				const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1588 
1589 				if (sofia_use_soa(tech_pvt)) {
1590 					nua_respond(tech_pvt->nh, SIP_200_OK,
1591 								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
1592 								SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
1593 								SOATAG_REUSE_REJECTED(1),
1594 								SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1),
1595 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1596 								TAG_END());
1597 				} else {
1598 					nua_respond(tech_pvt->nh, SIP_200_OK,
1599 								NUTAG_MEDIA_ENABLE(0),
1600 								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
1601 								SIPTAG_CONTENT_TYPE_STR("application/sdp"), SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str),
1602 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1603 								TAG_END());
1604 				}
1605 				switch_channel_mark_answered(channel);
1606 			}
1607 		}
1608 		break;
1609 	case SWITCH_MESSAGE_INDICATE_NOMEDIA:
1610 		{
1611 			sofia_glue_do_invite(session);
1612 		}
1613 		break;
1614 
1615 	case SWITCH_MESSAGE_INDICATE_MEDIA_REDIRECT:
1616 		{
1617 
1618 			if (zstr(msg->string_arg)) { /* no sdp requires proxy of ack */
1619 				switch_core_session_t *other_session;
1620 
1621 				if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
1622 					if (switch_core_session_compare(session, other_session)) {
1623 						private_object_t *other_tech_pvt = switch_core_session_get_private(other_session);
1624 						sofia_set_flag(other_tech_pvt, TFLAG_PASS_ACK);
1625 					}
1626 					switch_core_session_rwunlock(other_session);
1627 				}
1628 			}
1629 
1630 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Sending media re-direct:\n%s\n",
1631 							  switch_channel_get_name(channel), switch_str_nil(msg->string_arg));
1632 			switch_core_media_set_local_sdp(session, msg->string_arg, SWITCH_TRUE);
1633 
1634 			if (zstr(tech_pvt->mparams.local_sdp_str)) {
1635 				sofia_set_flag(tech_pvt, TFLAG_3PCC_INVITE);
1636 			}
1637 
1638 			sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
1639 
1640 			if (!switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
1641 				switch_channel_set_flag(channel, CF_REQ_MEDIA);
1642 			}
1643 			sofia_glue_do_invite(session);
1644 
1645 		}
1646 		break;
1647 
1648 	case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION:
1649 		{
1650 			switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options");
1651 			const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
1652 
1653 			if (!t38_options) {
1654 				nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END());
1655 				goto end_lock;
1656 			}
1657 
1658 			switch_core_media_start_udptl(tech_pvt->session, t38_options);
1659 
1660 			switch_core_media_set_udptl_image_sdp(tech_pvt->session, t38_options, msg->numeric_arg);
1661 
1662 			if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
1663 				char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_RESPONSE_HEADER_PREFIX);
1664 				if (sofia_use_soa(tech_pvt)) {
1665 					nua_respond(tech_pvt->nh, SIP_200_OK,
1666 								NUTAG_AUTOANSWER(0),
1667 								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
1668 								SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
1669 								SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
1670 								SOATAG_REUSE_REJECTED(1),
1671 								SOATAG_ORDERED_USER(1),
1672 								SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1),
1673 								TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
1674 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1675 								TAG_END());
1676 				} else {
1677 					nua_respond(tech_pvt->nh, SIP_200_OK,
1678 								NUTAG_AUTOANSWER(0),
1679 								NUTAG_MEDIA_ENABLE(0),
1680 								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
1681 								SIPTAG_CALL_INFO_STR(switch_channel_get_variable(tech_pvt->channel, SOFIA_SIP_HEADER_PREFIX "call_info")),
1682 								SIPTAG_CONTENT_TYPE_STR("application/sdp"),
1683 								SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str),
1684 								TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
1685 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1686 								TAG_END());
1687 				}
1688 				switch_safe_free(extra_headers);
1689 				sofia_set_flag_locked(tech_pvt, TFLAG_ANS);
1690 			}
1691 		}
1692 		break;
1693 
1694 	case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA:
1695 		{
1696 			switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options");
1697 
1698 			if (t38_options) {
1699 				switch_core_media_set_udptl_image_sdp(tech_pvt->session, t38_options, msg->numeric_arg);
1700 
1701 				if (!switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
1702 					switch_channel_set_flag(channel, CF_REQ_MEDIA);
1703 				}
1704 				sofia_set_flag_locked(tech_pvt, TFLAG_SENT_UPDATE);
1705 				sofia_glue_do_invite(session);
1706 			} else {
1707 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s Request to send IMAGE on channel with not t38 options.\n",
1708 								  switch_channel_get_name(channel));
1709 			}
1710 		}
1711 		break;
1712 
1713 	case SWITCH_MESSAGE_INDICATE_3P_NOMEDIA:
1714 		{
1715 			char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
1716 			const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
1717 
1718 			switch_channel_clear_flag(tech_pvt->channel, CF_MEDIA_ACK);
1719 			switch_channel_set_flag(tech_pvt->channel, CF_REQ_MEDIA);
1720 
1721 			sofia_glue_clear_soa(session, SWITCH_TRUE);
1722 
1723 			nua_invite(tech_pvt->nh,
1724 					   NUTAG_MEDIA_ENABLE(0),
1725 					   TAG_IF(msg->string_arg, SIPTAG_CONTENT_TYPE_STR("application/sdp")),
1726 					   SIPTAG_PAYLOAD_STR(msg->string_arg),
1727 					   TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
1728 					   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1729 					   TAG_END());
1730 
1731 			switch_safe_free(extra_headers);
1732 		}
1733 		break;
1734 	case SWITCH_MESSAGE_INDICATE_3P_MEDIA:
1735 		{
1736 			char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
1737 			const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
1738 
1739 			sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
1740 
1741 			switch_channel_clear_flag(tech_pvt->channel, CF_MEDIA_ACK);
1742 			switch_channel_clear_flag(tech_pvt->channel, CF_MEDIA_SET);
1743 			switch_channel_set_flag(tech_pvt->channel, CF_REQ_MEDIA);
1744 
1745 			sofia_glue_clear_soa(session, SWITCH_TRUE);
1746 
1747 			nua_invite(tech_pvt->nh, NUTAG_MEDIA_ENABLE(0), SIPTAG_PAYLOAD_STR(""),
1748 					   TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
1749 					   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1750 					   TAG_END());
1751 
1752 			switch_safe_free(extra_headers);
1753 		}
1754 		break;
1755 
1756 	case SWITCH_MESSAGE_INDICATE_MEDIA:
1757 		{
1758 			uint32_t send_invite = 1;
1759 			const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
1760 
1761 			switch_channel_clear_flag(channel, CF_PROXY_MODE);
1762 			switch_core_media_set_local_sdp(session, NULL, SWITCH_FALSE);
1763 
1764 			if (!(switch_channel_test_flag(channel, CF_ANSWERED) || switch_channel_test_flag(channel, CF_EARLY_MEDIA))) {
1765 				if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
1766 
1767 					switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
1768 					if (sofia_media_tech_media(tech_pvt, r_sdp, SDP_TYPE_REQUEST) != SWITCH_STATUS_SUCCESS) {
1769 						switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
1770 						status = SWITCH_STATUS_FALSE;
1771 						goto end_lock;
1772 					}
1773 					send_invite = 0;
1774 				}
1775 			}
1776 
1777 
1778 			switch_core_media_set_sdp_codec_string(tech_pvt->session, r_sdp, SDP_TYPE_RESPONSE);
1779 			switch_channel_set_variable(tech_pvt->channel, "absolute_codec_string", switch_channel_get_variable(tech_pvt->channel, "ep_codec_string"));
1780 			switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
1781 
1782 			if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) {
1783 				switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
1784 				goto end_lock;
1785 			}
1786 
1787 			switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 1);
1788 
1789 			if (!msg->numeric_arg) {
1790 				if (send_invite) {
1791 					if (!switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
1792 						switch_channel_set_flag(channel, CF_REQ_MEDIA);
1793 					}
1794 					sofia_glue_do_invite(session);
1795 				} else {
1796 					status = SWITCH_STATUS_FALSE;
1797 				}
1798 			}
1799 		}
1800 		break;
1801 
1802 	case SWITCH_MESSAGE_INDICATE_PHONE_EVENT:
1803 		{
1804 			const char *event = "talk";
1805 			const char *full_to = NULL;
1806 
1807 			if (!zstr(msg->string_arg) && strcasecmp(msg->string_arg, event)) {
1808 				if (!strcasecmp(msg->string_arg, "hold")) {
1809 					event = "hold";
1810 				} else if (strncasecmp(msg->string_arg, "talk", 4)) {
1811 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Invalid event.\n");
1812 				}
1813 			}
1814 
1815 			if (!switch_channel_test_flag(channel, CF_ANSWERED) && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
1816 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
1817 								  "Operation not permitted on an inbound non-answered call leg!\n");
1818 			} else {
1819 				const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1820 				full_to = switch_str_nil(switch_channel_get_variable(channel, "sip_full_to"));
1821 				nua_notify(tech_pvt->nh, NUTAG_NEWSUB(1), NUTAG_SUBSTATE(nua_substate_active),
1822 						   TAG_IF((full_to), SIPTAG_TO_STR(full_to)),SIPTAG_SUBSCRIPTION_STATE_STR("active"),
1823 						   SIPTAG_EVENT_STR(event),
1824 						   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1825 						   TAG_END());
1826 			}
1827 
1828 		}
1829 		break;
1830 	case SWITCH_MESSAGE_INDICATE_MESSAGE:
1831 		{
1832 			char ct[256] = "text/plain";
1833 			int ok = 0;
1834 			const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1835 
1836 			if (!zstr(msg->string_array_arg[3]) && !strcmp(msg->string_array_arg[3], tech_pvt->caller_profile->uuid)) {
1837 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Not sending message back to sender\n");
1838 				break;
1839 			}
1840 
1841 			if (switch_stristr("send_message", tech_pvt->x_freeswitch_support_remote)) {
1842 				ok = 1;
1843 			}
1844 
1845 			if (switch_true(switch_channel_get_variable(channel, "fs_send_unsupported_message"))) {
1846 				ok = 1;
1847 			}
1848 
1849 			if (ok) {
1850 				const char *pl = NULL;
1851 
1852 				if (!zstr(msg->string_array_arg[0]) && !zstr(msg->string_array_arg[1])) {
1853 					switch_snprintf(ct, sizeof(ct), "%s/%s", msg->string_array_arg[0], msg->string_array_arg[1]);
1854 				}
1855 
1856 				if (!zstr(msg->string_array_arg[2])) {
1857 					pl = msg->string_array_arg[2];
1858 				}
1859 
1860 				nua_message(tech_pvt->nh,
1861 							SIPTAG_CONTENT_TYPE_STR(ct),
1862 							TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
1863 							TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)),
1864 							TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1865 							TAG_END());
1866 			} else {
1867 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
1868 								  "%s send_message is not supported.\n", switch_channel_get_name(channel));
1869 			}
1870 		}
1871 		break;
1872 	case SWITCH_MESSAGE_INDICATE_INFO:
1873 		{
1874 			char ct[256] = "freeswitch/data";
1875 			int ok = 0;
1876 			const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1877 
1878 			if (switch_stristr("send_info", tech_pvt->x_freeswitch_support_remote)) {
1879 				ok = 1;
1880 			}
1881 
1882 			if (switch_true(switch_channel_get_variable_dup(channel, "fs_send_unsupported_info", SWITCH_FALSE, -1))) {
1883 				ok = 1;
1884 			}
1885 
1886 			if (ok) {
1887 				char *headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_INFO_HEADER_PREFIX);
1888 				const char *pl = NULL;
1889 
1890 				if (!zstr(msg->string_array_arg[0]) && !zstr(msg->string_array_arg[1])) {
1891 					switch_snprintf(ct, sizeof(ct), "%s/%s", msg->string_array_arg[0], msg->string_array_arg[1]);
1892 				}
1893 
1894 				if (!zstr(msg->string_array_arg[2])) {
1895 					pl = msg->string_array_arg[2];
1896 				}
1897 
1898 				nua_info(tech_pvt->nh,
1899 						 SIPTAG_CONTENT_TYPE_STR(ct),
1900 						 TAG_IF(!zstr(headers), SIPTAG_HEADER_STR(headers)),
1901 						 TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
1902 						 TAG_IF(pl, SIPTAG_PAYLOAD_STR(pl)),
1903 						 TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1904 						 TAG_END());
1905 
1906 				switch_safe_free(headers);
1907 			} else {
1908 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s send_info is not supported.\n", switch_channel_get_name(channel));
1909 			}
1910 		}
1911 		break;
1912 	case SWITCH_MESSAGE_INDICATE_SIMPLIFY:
1913 		{
1914 			char *ref_to, *ref_by;
1915 			const char *uuid;
1916 			const char *call_id = NULL, *to_user = NULL, *to_host = NULL, *to_tag = NULL, *from_tag = NULL, *from_user = NULL, *from_host = NULL;
1917 
1918 			if ((uuid = switch_channel_get_partner_uuid(channel))) {
1919 				switch_core_session_t *rsession;
1920 				if ((rsession = switch_core_session_locate(uuid))) {
1921 					switch_channel_t *rchannel = switch_core_session_get_channel(rsession);
1922 					call_id = switch_channel_get_variable(rchannel, "sip_call_id");
1923 
1924 					to_user = switch_channel_get_variable(rchannel, "sip_to_user");
1925 
1926 					if (switch_channel_direction(rchannel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
1927 						to_host = switch_channel_get_variable(rchannel, "sip_to_host");
1928 						from_user = switch_channel_get_variable(channel, "sip_from_user");
1929 						from_host = switch_channel_get_variable(channel, "sip_from_host");
1930 						to_tag = switch_channel_get_variable(rchannel, "sip_to_tag");
1931 						from_tag = switch_channel_get_variable(rchannel, "sip_from_tag");
1932 					} else {
1933 						to_host = switch_channel_get_variable(channel, "sip_to_host");
1934 						from_user = switch_channel_get_variable(rchannel, "sip_from_user");
1935 						from_host = switch_channel_get_variable(rchannel, "sip_from_host");
1936 						from_tag = switch_channel_get_variable(rchannel, "sip_to_tag");
1937 						to_tag = switch_channel_get_variable(rchannel, "sip_from_tag");
1938 					}
1939 
1940 					switch_core_session_rwunlock(rsession);
1941 				}
1942 			}
1943 
1944 			if (to_user && to_host && from_user && from_host && call_id && to_tag && from_tag) {
1945 				char in[512] = "", out[1536] = "";
1946 				const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1947 
1948 				switch_snprintf(in, sizeof(in), "%s;to-tag=%s;from-tag=%s", call_id, to_tag, from_tag);
1949 				switch_url_encode(in, out, sizeof(out));
1950 
1951 				ref_to = switch_mprintf("<sip:%s@%s?Replaces=%s>", to_user, to_host, out);
1952 				ref_by = switch_mprintf("<sip:%s@%s>", from_user, from_host);
1953 
1954 				nua_refer(tech_pvt->nh, SIPTAG_REFER_TO_STR(ref_to), SIPTAG_REFERRED_BY_STR(ref_by),
1955 						TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1956 						TAG_END());
1957 				switch_safe_free(ref_to);
1958 				switch_safe_free(ref_by);
1959 			}
1960 		}
1961 		break;
1962 	case SWITCH_MESSAGE_INDICATE_DISPLAY:
1963 		{
1964 			const char *name = NULL, *number = NULL;
1965 			const char *call_info = NULL;
1966 
1967 			if (!sofia_test_pflag(tech_pvt->profile, PFLAG_SEND_DISPLAY_UPDATE)) {
1968 				goto end_lock;
1969 			}
1970 
1971 			name = msg->string_array_arg[0];
1972 			number = msg->string_array_arg[1];
1973 			call_info = switch_channel_get_variable(channel, "presence_call_info_full");
1974 
1975 			if (!zstr(name) && strcmp(name, "_undef_")) {
1976 				char message[256] = "";
1977 				const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent");
1978 				const char *allow = switch_channel_get_variable(tech_pvt->channel, "sip_allow");
1979 				switch_event_t *event;
1980 				int update_allowed = 0;
1981 				const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
1982 
1983 				check_decode(name, tech_pvt->session);
1984 
1985 				if (allow) {
1986 					update_allowed = !!switch_stristr("UPDATE", allow);
1987 				}
1988 
1989 				if (zstr(number)) {
1990 					number = tech_pvt->caller_profile->destination_number;
1991 				}
1992 
1993 				switch_ivr_eavesdrop_update_display(session, name, number);
1994 
1995 				if (!sofia_test_flag(tech_pvt, TFLAG_UPDATING_DISPLAY) && switch_channel_test_flag(channel, CF_ANSWERED)) {
1996 					if (zstr(tech_pvt->last_sent_callee_id_name) || strcmp(tech_pvt->last_sent_callee_id_name, name) ||
1997 						zstr(tech_pvt->last_sent_callee_id_number) || strcmp(tech_pvt->last_sent_callee_id_number, number)) {
1998 
1999 						if (switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote)) {
2000 							snprintf(message, sizeof(message), "X-FS-Display-Name: %s\nX-FS-Display-Number: %s\n", name, number);
2001 
2002 							if (switch_channel_test_flag(tech_pvt->channel, CF_LAZY_ATTENDED_TRANSFER)) {
2003 								snprintf(message + strlen(message), sizeof(message) - strlen(message), "X-FS-Lazy-Attended-Transfer: true\n");
2004 								switch_channel_clear_flag(tech_pvt->channel, CF_LAZY_ATTENDED_TRANSFER);
2005 								switch_channel_clear_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER);
2006 							}
2007 
2008 							if (switch_channel_test_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER)) {
2009 								snprintf(message + strlen(message), sizeof(message) - strlen(message), "X-FS-Attended-Transfer: true\n");
2010 								switch_channel_clear_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER);
2011 							}
2012 
2013 							nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/update_display"),
2014 									 TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)),
2015 									 TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
2016 									 TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2017 									 TAG_END());
2018 						} else if (ua && switch_stristr("snom", ua)) {
2019 							const char *ver_str = NULL;
2020 							int version = 0;
2021 
2022 							ver_str = switch_stristr( "/", ua);
2023 
2024 							if ( ver_str ) {
2025 								char *argv[4] = { 0 };
2026 								char *dotted = strdup( ver_str + 1 );
2027 								switch_assert(dotted);
2028 								switch_separate_string(dotted, '.', argv, (sizeof(argv) / sizeof(argv[0])));
2029 								if ( argv[0] && argv[1] && argv[2] ) {
2030 									version = ( atoi(argv[0]) * 10000 )  + ( atoi(argv[1]) * 100 ) + atoi(argv[2]);
2031 								}
2032 								switch_safe_free( dotted );
2033 							}
2034 
2035 							if ( version >= 80424 ) {
2036 								if (zstr(name)) {
2037 									snprintf(message, sizeof(message), "From: %s\r\nTo:\r\n", number);
2038 								} else {
2039 									snprintf(message, sizeof(message), "From: \"%s\" %s\r\nTo:\r\n", name, number);
2040 								}
2041 							} else {
2042 								if (zstr(name)) {
2043 									snprintf(message, sizeof(message), "From:\r\nTo: %s\r\n", number);
2044 								} else {
2045 									snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", name, number);
2046 								}
2047 							}
2048 
2049 							nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
2050 									 TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), SIPTAG_PAYLOAD_STR(message), TAG_END());
2051 						} else if (update_allowed && ua && (switch_stristr("polycom", ua) ||
2052 									  (switch_stristr("aastra", ua) && !switch_stristr("Intelligate", ua)) ||
2053 									  (switch_stristr("cisco/spa50", ua) ||
2054 									  switch_stristr("cisco/spa525", ua)) ||
2055 									  switch_stristr("cisco/spa30", ua) ||
2056 									  switch_stristr("Grandstream", ua) ||
2057 									  switch_stristr("Yealink", ua) ||
2058 									  switch_stristr("Mitel", ua) ||
2059 									  switch_stristr("Panasonic", ua))) {
2060 							snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <sip:%s@%s>", name, number, tech_pvt->profile->sipip);
2061 
2062 							sofia_set_flag_locked(tech_pvt, TFLAG_UPDATING_DISPLAY);
2063 							nua_update(tech_pvt->nh,
2064 									   NUTAG_SESSION_TIMER(tech_pvt->session_timeout),
2065 									   NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher),
2066 									   NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher),
2067 									   TAG_IF(!zstr(tech_pvt->privacy), SIPTAG_PRIVACY_STR(tech_pvt->privacy)),
2068 									   TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
2069 									   TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)),
2070 									   TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)),
2071 									   TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
2072 									   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2073 									   TAG_END());
2074 						}
2075 
2076 						tech_pvt->last_sent_callee_id_name = switch_core_session_strdup(tech_pvt->session, name);
2077 						tech_pvt->last_sent_callee_id_number = switch_core_session_strdup(tech_pvt->session, number);
2078 
2079 
2080 						if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) {
2081 							const char *uuid = switch_channel_get_partner_uuid(channel);
2082 							switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "SEND");
2083 
2084 
2085 							switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sent-Callee-ID-Name", name);
2086 							switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Sent-Callee-ID-Number", number);
2087 
2088 							//switch_channel_set_profile_var(channel, "callee_id_name", name);
2089 							//switch_channel_set_profile_var(channel, "callee_id_number", number);
2090 
2091 							if (uuid) {
2092 								switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid);
2093 							}
2094 							switch_channel_event_set_data(channel, event);
2095 							switch_event_fire(&event);
2096 						}
2097 					} else {
2098 						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Not sending same id again \"%s\" <%s>\n", name, number);
2099 					}
2100 				}
2101 			}
2102 		}
2103 		break;
2104 
2105 	case SWITCH_MESSAGE_INDICATE_HOLD:
2106 		{
2107 
2108 			if (msg->numeric_arg) {
2109 				switch_core_media_toggle_hold(session, 1);
2110 			} else {
2111 
2112 				sofia_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
2113 				switch_channel_set_flag(channel, CF_LEG_HOLDING);
2114 				sofia_glue_do_invite(session);
2115 				if (!zstr(msg->string_arg)) {
2116 					char message[256] = "";
2117 					const char *ua = switch_channel_get_variable(tech_pvt->channel, "sip_user_agent");
2118 					const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
2119 
2120 					if (ua && switch_stristr("snom", ua)) {
2121 						snprintf(message, sizeof(message), "From:\r\nTo: \"%s\" %s\r\n", msg->string_arg, tech_pvt->caller_profile->destination_number);
2122 						nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
2123 								 TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
2124 								 SIPTAG_PAYLOAD_STR(message),
2125 								 TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2126 								 TAG_END());
2127 					} else if (ua && switch_stristr("polycom", ua)) {
2128 						snprintf(message, sizeof(message), "P-Asserted-Identity: \"%s\" <%s>", msg->string_arg, tech_pvt->caller_profile->destination_number);
2129 						nua_update(tech_pvt->nh,
2130 								   NUTAG_SESSION_TIMER(tech_pvt->session_timeout),
2131 								   NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher),
2132 								   NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher),
2133 								   TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)),
2134 								   TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)),
2135 								   TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
2136 								   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2137 								   TAG_END());
2138 					}
2139 				}
2140 			}
2141 		}
2142 		break;
2143 
2144 	case SWITCH_MESSAGE_INDICATE_UNHOLD:
2145 		{
2146 			sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
2147 			switch_channel_clear_flag(channel, CF_LEG_HOLDING);
2148 			sofia_glue_do_invite(session);
2149 		}
2150 		break;
2151 	case SWITCH_MESSAGE_INDICATE_REDIRECT:
2152 
2153 #define MAX_REDIR 128
2154 
2155 		if (!zstr(msg->string_arg)) {
2156 
2157 			if (!switch_channel_test_flag(channel, CF_ANSWERED) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) {
2158 				char *mydest = (char *) msg->string_arg;
2159 				char *argv[MAX_REDIR] = { 0 };
2160 				char *mydata = NULL, *newdest = NULL;
2161 				int argc = 0, i;
2162 				switch_size_t len = 0;
2163 				switch_call_cause_t sip_redirect_cause = SWITCH_CAUSE_NORMAL_UNSPECIFIED;
2164 				char *dest = switch_core_session_strdup(session, mydest);
2165 
2166 				if ((argc = switch_separate_string(dest, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) >= 2) {
2167 					const char *redirect_cause = argv[1];
2168 					sip_redirect_cause = switch_channel_str2cause(redirect_cause);
2169 				}
2170 
2171 				if (strchr(dest, ',')) {
2172 					mydata = dest;
2173 					len = strlen(mydata) * 2;
2174 					newdest = switch_core_session_alloc(session, len);
2175 
2176 					argc = switch_split(mydata, ',', argv);
2177 
2178 					for (i = 0; i < argc; i++) {
2179 						if (!strchr(argv[i], '<') && !strchr(argv[i], '>')) {
2180 							if (argc > 1) {
2181 								if (i == argc - 1) {
2182 									switch_snprintf(newdest + strlen(newdest), len - strlen(newdest), "\"unknown\" <%s>;q=%1.3f",
2183 													argv[i], (double)((double)(MAX_REDIR + 1 - i))/1000);
2184 								} else {
2185 									switch_snprintf(newdest + strlen(newdest), len - strlen(newdest), "\"unknown\" <%s>;q=%1.3f,",
2186 													argv[i], (double)((double)(MAX_REDIR + 1 - i))/1000);
2187 								}
2188 							} else {
2189 								if (i == argc - 1) {
2190 									switch_snprintf(newdest + strlen(newdest), len - strlen(newdest), "\"unknown\" <%s>", argv[i]);
2191 								} else {
2192 									switch_snprintf(newdest + strlen(newdest), len - strlen(newdest), "\"unknown\" <%s>,", argv[i]);
2193 								}
2194 							}
2195 						} else {
2196 							if (i == argc - 1) {
2197 								switch_snprintf(newdest + strlen(newdest), len - strlen(newdest), "%s", argv[i]);
2198 							} else {
2199 								switch_snprintf(newdest + strlen(newdest), len - strlen(newdest), "%s,", argv[i]);
2200 							}
2201 						}
2202 					}
2203 
2204 					dest = newdest;
2205 				} else {
2206 
2207 					if (!strchr(dest, '<') && !strchr(dest, '>')) {
2208 						dest = switch_core_session_sprintf(session, "\"unknown\" <%s>", dest);
2209 					}
2210 				}
2211 
2212 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Redirecting to %s\n", dest);
2213 
2214 				tech_pvt->respond_dest = dest;
2215 
2216 				if (argc > 1) {
2217 					tech_pvt->respond_code = 300;
2218 					tech_pvt->respond_phrase = "Multiple Choices";
2219 				} else {
2220 					tech_pvt->respond_code = 302;
2221 					tech_pvt->respond_phrase = "Moved Temporarily";
2222 				}
2223 
2224 				if (sip_redirect_cause == SWITCH_CAUSE_NONE) {
2225 					sip_redirect_cause = SWITCH_CAUSE_NORMAL_UNSPECIFIED;
2226 				}
2227 				switch_channel_hangup(tech_pvt->channel, sip_redirect_cause);
2228 
2229 			} else {
2230 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Too late for redirecting, already answered\n");
2231 
2232 			}
2233 		}
2234 		break;
2235 	case SWITCH_MESSAGE_INDICATE_RESPOND:
2236 		{
2237 			const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
2238 
2239 			if (switch_channel_test_flag(tech_pvt->channel, CF_AWAITING_STREAM_CHANGE)) {
2240 				switch_channel_clear_flag(tech_pvt->channel, CF_AWAITING_STREAM_CHANGE);
2241 
2242 				switch_core_session_local_crypto_key(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
2243 				switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
2244 
2245 				if (sofia_use_soa(tech_pvt)) {
2246 					nua_respond(tech_pvt->nh, SIP_200_OK,
2247 								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2248 								SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
2249 								SOATAG_REUSE_REJECTED(1),
2250 								SOATAG_AUDIO_AUX("cn telephone-event"),
2251 								TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_DISABLE_100REL), NUTAG_INCLUDE_EXTRA_SDP(1)),
2252 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2253 								TAG_END());
2254 				} else {
2255 					nua_respond(tech_pvt->nh, SIP_200_OK,
2256 								NUTAG_MEDIA_ENABLE(0),
2257 								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2258 								SIPTAG_CONTENT_TYPE_STR("application/sdp"),
2259 								SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str),
2260 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2261 								TAG_END());
2262 				}
2263 			}
2264 
2265 			if (msg->numeric_arg || msg->string_arg) {
2266 				int code = msg->numeric_arg;
2267 				const char *reason = NULL;
2268 
2269 				if (code > 0) {
2270 					reason = msg->string_arg;
2271 				} else {
2272 					if (!zstr(msg->string_arg)) {
2273 						if ((code = atoi(msg->string_arg))) {
2274 							if ((reason = strchr(msg->string_arg, ' '))) {
2275 								reason++;
2276 							}
2277 						}
2278 					}
2279 				}
2280 
2281 				if (!code) {
2282 					code = 488;
2283 				}
2284 
2285 				if (!switch_channel_test_flag(channel, CF_ANSWERED) && code >= 300) {
2286 					if (sofia_test_flag(tech_pvt, TFLAG_BYE)) {
2287 						goto end_lock;
2288 					}
2289 				}
2290 
2291 				if (zstr(reason) && code != 407 && code != 302) {
2292 					reason = sip_status_phrase(code);
2293 					if (zstr(reason)) {
2294 						reason = "Because";
2295 					}
2296 				}
2297 
2298 				/* Dialplan should really use acknowledge_call application instead of respond application to send 100 */
2299 				if (code == 100) {
2300 					status = sofia_acknowledge_call(session);
2301 					goto end_lock;
2302 				}
2303 
2304 				if (tech_pvt->proxy_refer_uuid) {
2305 					if (tech_pvt->proxy_refer_msg) {
2306 						nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason),
2307 									SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2308 									SIPTAG_EXPIRES_STR("60"),
2309 									NUTAG_WITH_THIS_MSG(tech_pvt->proxy_refer_msg),
2310 									TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2311 									TAG_END());
2312 						msg_ref_destroy(tech_pvt->proxy_refer_msg);
2313 						tech_pvt->proxy_refer_msg = NULL;
2314 					}
2315 					goto end_lock;
2316 				}
2317 
2318 				if (code == 302 && !zstr(msg->string_arg)) {
2319 					char *p;
2320 
2321 					if ((p = strchr(msg->string_arg, ' '))) {
2322 						*p = '\0';
2323 						msg->string_arg = p;
2324 					}
2325 
2326 					msg->message_id = SWITCH_MESSAGE_INDICATE_REDIRECT;
2327 					switch_core_session_receive_message(session, msg);
2328 					goto end_lock;
2329 				} else {
2330 					if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
2331 						char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX);
2332 						char *sdp = (char *) msg->pointer_arg;
2333 
2334 						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Responding with %d [%s]\n", code, reason);
2335 						sofia_clear_flag(tech_pvt, TFLAG_REINVITED);
2336 
2337 						if (!zstr((sdp))) {
2338 							if (!strcasecmp(sdp, "t38")) {
2339 								switch_t38_options_t *t38_options = switch_channel_get_private(tech_pvt->channel, "t38_options");
2340 								if (t38_options) {
2341 									switch_core_media_set_udptl_image_sdp(tech_pvt->session, t38_options, 0);
2342 									if (switch_core_media_ready(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO)) {
2343 										switch_channel_clear_flag(tech_pvt->channel, CF_NOTIMER_DURING_BRIDGE);
2344 										switch_core_media_udptl_mode(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO);
2345 									}
2346 								}
2347 							} else {
2348 								switch_core_media_set_local_sdp(session, sdp, SWITCH_TRUE);
2349 							}
2350 
2351 							if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
2352 								switch_core_media_patch_sdp(tech_pvt->session);
2353 								switch_core_media_proxy_remote_addr(session, NULL);
2354 							}
2355 
2356 							if (sofia_use_soa(tech_pvt)) {
2357 								nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2358 											SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
2359 											SOATAG_REUSE_REJECTED(1),
2360 											SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1),
2361 											TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
2362 											TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2363 											TAG_END());
2364 							} else {
2365 								nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason), SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2366 											NUTAG_MEDIA_ENABLE(0),
2367 											SIPTAG_CONTENT_TYPE_STR("application/sdp"),
2368 											SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str),
2369 											TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
2370 											TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2371 											TAG_END());
2372 							}
2373 
2374 							if (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC)) {
2375 								/* Unlock the session signal to allow the ack to make it in */
2376 								// Maybe we should timeout?
2377 								switch_mutex_unlock(tech_pvt->sofia_mutex);
2378 
2379 								while (switch_channel_ready(channel) && !sofia_test_flag(tech_pvt, TFLAG_3PCC_HAS_ACK)) {
2380 									switch_ivr_parse_all_events(session);
2381 									switch_yield(10000);
2382 								}
2383 
2384 								/*  Regain lock on sofia */
2385 								switch_mutex_lock(tech_pvt->sofia_mutex);
2386 
2387 								switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "3PCC-PROXY, Done waiting for ACK\n");
2388 								sofia_clear_flag(tech_pvt, TFLAG_3PCC);
2389 								sofia_clear_flag(tech_pvt, TFLAG_3PCC_HAS_ACK);
2390 								switch_core_session_pass_indication(session, SWITCH_MESSAGE_INDICATE_ANSWER);
2391 							}
2392 						} else {
2393 							if (msg->numeric_arg && !(switch_channel_test_flag(channel, CF_ANSWERED) && code == 488)) {
2394 								if (code > 399) {
2395 									switch_call_cause_t cause = sofia_glue_sip_cause_to_freeswitch(code);
2396 									if (code == 401 || cause == 407) cause = SWITCH_CAUSE_USER_CHALLENGE;
2397 
2398 									tech_pvt->respond_code = code;
2399 									tech_pvt->respond_phrase = switch_core_session_strdup(tech_pvt->session, reason);
2400 									switch_channel_hangup(tech_pvt->channel, cause);
2401 								} else {
2402 									switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot respond.\n");
2403 								}
2404 							} else {
2405 								nua_respond(tech_pvt->nh, code, su_strdup(nua_handle_home(tech_pvt->nh), reason),
2406 											SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2407 											TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
2408 											TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2409 											TAG_END());
2410 							}
2411 
2412 						}
2413 						switch_safe_free(extra_headers);
2414 					}
2415 				}
2416 
2417 			}
2418 		}
2419 		break;
2420 	case SWITCH_MESSAGE_INDICATE_ALERTING:
2421 		{
2422 			char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX);
2423 			const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full");
2424 			char *cid = generate_pai_str(tech_pvt);
2425 			const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
2426 
2427 			nua_respond(tech_pvt->nh, SIP_180_RINGING,
2428 						SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2429 						TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
2430 						TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
2431 						TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)),
2432 						TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
2433 							   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)),
2434 						TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2435 						TAG_END());
2436 		}
2437 		break;
2438 	case SWITCH_MESSAGE_INDICATE_ACKNOWLEDGE_CALL:
2439 		status = sofia_acknowledge_call(session);
2440 		break;
2441 	case SWITCH_MESSAGE_INDICATE_RINGING:
2442 		{
2443 			switch_ring_ready_t ring_ready_val = msg->numeric_arg;
2444 
2445 			if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) {
2446 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying");
2447 			}
2448 
2449 			if (!switch_channel_test_flag(channel, CF_RING_READY) && !sofia_test_flag(tech_pvt, TFLAG_BYE) &&
2450 				!switch_channel_test_flag(channel, CF_EARLY_MEDIA) && !switch_channel_test_flag(channel, CF_ANSWERED)) {
2451 				char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX);
2452 				const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full");
2453 				char *cid = generate_pai_str(tech_pvt);
2454 				const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
2455 
2456 				/* Set sip_to_tag to local tag for inbound channels. */
2457 				if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) {
2458 					const char* to_tag = "";
2459 					to_tag = switch_str_nil(nta_leg_get_tag(tech_pvt->nh->nh_ds->ds_leg));
2460 					if(to_tag) {
2461 						switch_channel_set_variable(channel, "sip_to_tag", to_tag);
2462 					}
2463 				}
2464 
2465 				switch (ring_ready_val) {
2466 
2467 				case SWITCH_RING_READY_QUEUED:
2468 
2469 					nua_respond(tech_pvt->nh, SIP_182_QUEUED,
2470 								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2471 								TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
2472 								TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
2473 								TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)),
2474 								TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
2475 									   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)),
2476 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2477 								TAG_END());
2478 					break;
2479 
2480 				case SWITCH_RING_READY_RINGING:
2481 				default:
2482 
2483 					nua_respond(tech_pvt->nh, SIP_180_RINGING,
2484 								SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2485 								TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
2486 								TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
2487 								TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)),
2488 								TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
2489 									   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)),
2490 								TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2491 								TAG_END());
2492 
2493 					break;
2494 				}
2495 
2496 
2497 				switch_safe_free(extra_header);
2498 				switch_channel_mark_ring_ready(channel);
2499 			}
2500 		}
2501 		break;
2502 	case SWITCH_MESSAGE_INDICATE_ANSWER:
2503 		status = sofia_answer_channel(session);
2504 		break;
2505 	case SWITCH_MESSAGE_INDICATE_PROGRESS:
2506 		{
2507 			char *sticky = NULL;
2508 			const char *val = NULL;
2509 			const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full");
2510 			const char *b_sdp = NULL;
2511 			int is_proxy = 0, is_3pcc_proxy = 0;
2512 			int send_sip_code = 183;
2513 			const char * p_send_sip_msg = sip_183_Session_progress;
2514 
2515 			if(sofia_acknowledge_call(session) == SWITCH_STATUS_SUCCESS) {
2516 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Dialplan did not acknowledge_call; sent 100 Trying");
2517 			}
2518 
2519 			b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE);
2520 			is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA));
2521 			is_3pcc_proxy = (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC));
2522 
2523 			// send 180 instead of 183 if variable "early_use_180" is "true"
2524 			if (switch_true(switch_channel_get_variable(channel, "early_use_180"))) {
2525 				send_sip_code = 180;
2526 				p_send_sip_msg = sip_180_Ringing;
2527 			}
2528 
2529 			if (b_sdp && is_proxy && !is_3pcc_proxy) {
2530 				switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE);
2531 
2532 				if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
2533 					switch_core_media_patch_sdp(tech_pvt->session);
2534 					if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
2535 						status = SWITCH_STATUS_FALSE;
2536 						goto end_lock;
2537 					}
2538 				}
2539 			}
2540 
2541 			if (!sofia_test_flag(tech_pvt, TFLAG_ANS) && !sofia_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
2542 
2543 				sofia_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
2544 				switch_log_printf(SWITCH_CHANNEL_ID_SESSION, msg->_file, msg->_func, msg->_line,
2545 								  (const char*)session, SWITCH_LOG_INFO, "Sending early media\n");
2546 
2547 				/* Transmit 183 Progress with SDP */
2548 				if (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
2549 					const char *sdp = NULL;
2550 					if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
2551 						switch_core_media_set_local_sdp(session, sdp, SWITCH_TRUE);
2552 					}
2553 					if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
2554 
2555 						switch_core_media_patch_sdp(tech_pvt->session);
2556 
2557 						if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
2558 							status = SWITCH_STATUS_FALSE;
2559 							goto end_lock;
2560 						}
2561 					}
2562 				} else {
2563 					if (sofia_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION) ||
2564 						switch_core_media_codec_chosen(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO) != SWITCH_STATUS_SUCCESS) {
2565 						sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
2566 						if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
2567 							const char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
2568 
2569 
2570 							switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
2571 							if (zstr(r_sdp) || sofia_media_tech_media(tech_pvt, r_sdp, SDP_TYPE_REQUEST) != SWITCH_STATUS_SUCCESS) {
2572 								switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
2573 												  "CODEC NEGOTIATION ERROR.  SDP:\n%s\n", r_sdp ? r_sdp : "NO SDP!");
2574 								switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
2575 								//nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
2576 								status = SWITCH_STATUS_FALSE;
2577 								goto end_lock;
2578 							}
2579 						}
2580 					}
2581 
2582 					switch_channel_check_zrtp(tech_pvt->channel);
2583 
2584 					if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) {
2585 						switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2586 						goto end_lock;
2587 					}
2588 					switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0);
2589 					if (sofia_media_activate_rtp(tech_pvt) != SWITCH_STATUS_SUCCESS) {
2590 						switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
2591 					}
2592 					if (tech_pvt->mparams.local_sdp_str) {
2593 						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Ring SDP:\n%s\n", tech_pvt->mparams.local_sdp_str);
2594 					}
2595 				}
2596 				switch_channel_mark_pre_answered(channel);
2597 
2598 
2599 				if (sofia_test_flag(tech_pvt, TFLAG_NAT) ||
2600 					(val = switch_channel_get_variable(channel, "sip-force-contact")) ||
2601 					((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val))) {
2602 					sticky = tech_pvt->record_route;
2603 					switch_channel_set_variable(channel, "sip_nat_detected", "true");
2604 				}
2605 
2606 				if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) {
2607 					char *extra_header = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX);
2608 					char *cid = NULL;
2609 					const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
2610 
2611 					cid = generate_pai_str(tech_pvt);
2612 
2613 
2614 					if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) &&
2615 						tech_pvt->mparams.early_sdp && strcmp(tech_pvt->mparams.early_sdp, tech_pvt->mparams.local_sdp_str)) {
2616 						/* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless
2617 						   we do so in this case we will abandon the SOA rules and go rogue.
2618 						 */
2619 						sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
2620 					}
2621 
2622 					tech_pvt->mparams.early_sdp = switch_core_session_strdup(tech_pvt->session, tech_pvt->mparams.local_sdp_str);
2623 
2624 					if (sofia_use_soa(tech_pvt)) {
2625 						nua_respond(tech_pvt->nh,
2626 									send_sip_code, p_send_sip_msg,
2627 									NUTAG_AUTOANSWER(0),
2628 									TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
2629 									TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
2630 									SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2631 									SOATAG_REUSE_REJECTED(1),
2632 									SOATAG_RTP_SELECT(1),
2633 									SOATAG_ADDRESS(tech_pvt->mparams.adv_sdp_audio_ip),
2634 									SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"),
2635 									TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
2636 									TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)),
2637 									TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
2638 										   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)),
2639 									TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2640 									TAG_END());
2641 					} else {
2642 						nua_respond(tech_pvt->nh,
2643 									send_sip_code, p_send_sip_msg,
2644 									NUTAG_AUTOANSWER(0),
2645 									NUTAG_MEDIA_ENABLE(0),
2646 									TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
2647 									TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
2648 									SIPTAG_CONTACT_STR(tech_pvt->reply_contact),
2649 									SIPTAG_CONTENT_TYPE_STR("application/sdp"),
2650 									SIPTAG_PAYLOAD_STR(tech_pvt->mparams.local_sdp_str),
2651 									TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)),
2652 									TAG_IF(!zstr(extra_header), SIPTAG_HEADER_STR(extra_header)),
2653 									TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
2654 										   SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)),
2655 									TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
2656 									TAG_END());
2657 					}
2658 					switch_safe_free(extra_header);
2659 				}
2660 			}
2661 		}
2662 		break;
2663 
2664 	case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:
2665 		{
2666 			switch_t38_options_t *t38_options = switch_channel_get_private(channel, "t38_options");
2667 
2668 			if (!t38_options) {
2669 				const char *session_id_header = sofia_glue_session_id_header(tech_pvt->session, tech_pvt->profile);
2670 
2671 				nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)), TAG_END());
2672 			}
2673 		}
2674 		break;
2675 
2676 	case SWITCH_MESSAGE_INDICATE_SESSION_ID:
2677 		{
2678 			if (sofia_test_pflag(tech_pvt->profile, PFLAG_RFC7989_SESSION_ID) && switch_channel_test_flag(channel, CF_ANSWERED)) {
2679 				sofia_glue_do_invite(session);
2680 			}
2681 		}
2682 		break;
2683 
2684 	default:
2685 		break;
2686 	}
2687 
2688   end_lock:
2689 
2690 	//if (msg->message_id == SWITCH_MESSAGE_INDICATE_ANSWER || msg->message_id == SWITCH_MESSAGE_INDICATE_PROGRESS) {
2691 	//sofia_send_callee_id(session, NULL, NULL);
2692 	//}
2693 
2694 	switch_mutex_unlock(tech_pvt->sofia_mutex);
2695 
2696   end:
2697 
2698 	if (switch_channel_down(channel) || sofia_test_flag(tech_pvt, TFLAG_BYE)) {
2699 		status = SWITCH_STATUS_FALSE;
2700 	}
2701 
2702 	return status;
2703 
2704 }
2705 
sofia_receive_event(switch_core_session_t * session,switch_event_t * event)2706 static switch_status_t sofia_receive_event(switch_core_session_t *session, switch_event_t *event)
2707 {
2708 	struct private_object *tech_pvt = switch_core_session_get_private(session);
2709 	char *body;
2710 	nua_handle_t *msg_nh;
2711 
2712 	switch_assert(tech_pvt != NULL);
2713 
2714 	if (!(body = switch_event_get_body(event))) {
2715 		body = "";
2716 	}
2717 
2718 	if (tech_pvt->hash_key) {
2719 		switch_mutex_lock(tech_pvt->sofia_mutex);
2720 		msg_nh = nua_handle(tech_pvt->profile->nua, NULL,
2721 							SIPTAG_FROM_STR(tech_pvt->chat_from),
2722 							NUTAG_URL(tech_pvt->chat_to), SIPTAG_TO_STR(tech_pvt->chat_to), TAG_END());
2723 		nua_handle_bind(msg_nh, &mod_sofia_globals.destroy_private);
2724 		nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END());
2725 		switch_mutex_unlock(tech_pvt->sofia_mutex);
2726 	}
2727 
2728 	return SWITCH_STATUS_SUCCESS;
2729 }
2730 
2731 typedef switch_status_t (*sofia_command_t) (char **argv, int argc, switch_stream_handle_t *stream);
2732 
2733 const char *sofia_state_names[] = {
2734 	"UNREGED",
2735 	"TRYING",
2736 	"REGISTER",
2737 	"REGED",
2738 	"UNREGISTER",
2739 	"FAILED",
2740 	"FAIL_WAIT",
2741 	"EXPIRED",
2742 	"NOREG",
2743 	"TIMEOUT",
2744 	NULL
2745 };
2746 
sofia_state_string(int state)2747 const char *sofia_state_string(int state)
2748 {
2749 	if (state >= REG_STATE_LAST) return "";
2750 
2751 	return sofia_state_names[state];
2752 }
2753 
2754 struct cb_helper_sql2str {
2755 	char *buf;
2756 	size_t len;
2757 	int matches;
2758 };
2759 
2760 struct cb_helper {
2761 	uint32_t row_process;
2762 	sofia_profile_t *profile;
2763 	switch_stream_handle_t *stream;
2764 	switch_bool_t dedup;
2765 };
2766 
2767 
2768 
show_reg_callback(void * pArg,int argc,char ** argv,char ** columnNames)2769 static int show_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
2770 {
2771 	struct cb_helper *cb = (struct cb_helper *) pArg;
2772 	char exp_buf[128] = "";
2773 	int exp_secs = 0;
2774 	switch_time_exp_t tm;
2775 
2776 	cb->row_process++;
2777 
2778 	if (argv[6]) {
2779 		time_t now = switch_epoch_time_now(NULL);
2780 		switch_time_t etime = atoi(argv[6]);
2781 		switch_size_t retsize;
2782 
2783 		exp_secs = (int)(etime - now);
2784 		switch_time_exp_lt(&tm, switch_time_from_sec(etime));
2785 		switch_strftime_nocheck(exp_buf, &retsize, sizeof(exp_buf), "%Y-%m-%d %T", &tm);
2786 	}
2787 
2788 	cb->stream->write_function(cb->stream,
2789 							   "Call-ID:    \t%s\n"
2790 							   "User:       \t%s@%s\n"
2791 							   "Contact:    \t%s\n"
2792 							   "Agent:      \t%s\n"
2793 							   "Status:     \t%s(%s) EXP(%s) EXPSECS(%d)\n"
2794 							   "Ping-Status:\t%s\n"
2795 							   "Ping-Time:\t%0.2f\n"
2796 							   "Host:       \t%s\n"
2797 							   "IP:         \t%s\n"
2798 							   "Port:       \t%s\n"
2799 							   "Auth-User:  \t%s\n"
2800 							   "Auth-Realm: \t%s\n"
2801 							   "MWI-Account:\t%s@%s\n\n",
2802 							   switch_str_nil(argv[0]), switch_str_nil(argv[1]), switch_str_nil(argv[2]), switch_str_nil(argv[3]),
2803 							   switch_str_nil(argv[7]), switch_str_nil(argv[4]), switch_str_nil(argv[5]), exp_buf, exp_secs, switch_str_nil(argv[18]),
2804 							   (float)atoll(switch_str_nil(argv[19]))/1000, switch_str_nil(argv[11]), switch_str_nil(argv[12]),
2805 							   switch_str_nil(argv[13]), switch_str_nil(argv[14]),
2806 							   switch_str_nil(argv[15]), switch_str_nil(argv[16]), switch_str_nil(argv[17]));
2807 	return 0;
2808 }
2809 
show_reg_callback_xml(void * pArg,int argc,char ** argv,char ** columnNames)2810 static int show_reg_callback_xml(void *pArg, int argc, char **argv, char **columnNames)
2811 {
2812 	struct cb_helper *cb = (struct cb_helper *) pArg;
2813 	char exp_buf[128] = "";
2814 	switch_time_exp_t tm;
2815 	const int buflen = 2048;
2816 	char xmlbuf[2048];
2817 	int exp_secs = 0;
2818 
2819 	cb->row_process++;
2820 
2821 	if (argv[6]) {
2822 		time_t now = switch_epoch_time_now(NULL);
2823 		switch_time_t etime = atoi(argv[6]);
2824 		switch_size_t retsize;
2825 
2826 		exp_secs = (int)(etime - now);
2827 		switch_time_exp_lt(&tm, switch_time_from_sec(etime));
2828 		switch_strftime_nocheck(exp_buf, &retsize, sizeof(exp_buf), "%Y-%m-%d %T", &tm);
2829 	}
2830 
2831 	cb->stream->write_function(cb->stream, "    <registration>\n");
2832 	cb->stream->write_function(cb->stream, "        <call-id>%s</call-id>\n", switch_str_nil(argv[0]));
2833 	cb->stream->write_function(cb->stream, "        <user>%s@%s</user>\n", switch_str_nil(argv[1]), switch_str_nil(argv[2]));
2834 	cb->stream->write_function(cb->stream, "        <contact>%s</contact>\n", switch_amp_encode(switch_str_nil(argv[3]), xmlbuf, buflen));
2835 	cb->stream->write_function(cb->stream, "        <agent>%s</agent>\n", switch_amp_encode(switch_str_nil(argv[7]), xmlbuf, buflen));
2836 	cb->stream->write_function(cb->stream, "        <status>%s(%s) exp(%s) expsecs(%d)</status>\n", switch_str_nil(argv[4]), switch_str_nil(argv[5]),
2837 							   exp_buf, exp_secs);
2838 	cb->stream->write_function(cb->stream, "        <ping-status>%s</ping-status>\n", switch_str_nil(argv[18]));
2839 	cb->stream->write_function(cb->stream, "        <ping-time>%0.2f</ping-time>\n", (float)atoll(switch_str_nil(argv[19]))/1000);
2840 	cb->stream->write_function(cb->stream, "        <host>%s</host>\n", switch_str_nil(argv[11]));
2841 	cb->stream->write_function(cb->stream, "        <network-ip>%s</network-ip>\n", switch_str_nil(argv[12]));
2842 	cb->stream->write_function(cb->stream, "        <network-port>%s</network-port>\n", switch_str_nil(argv[13]));
2843 	cb->stream->write_function(cb->stream, "        <sip-auth-user>%s</sip-auth-user>\n",
2844 							   switch_url_encode(switch_str_nil(argv[14]), xmlbuf, sizeof(xmlbuf)));
2845 	cb->stream->write_function(cb->stream, "        <sip-auth-realm>%s</sip-auth-realm>\n", switch_str_nil(argv[15]));
2846 	cb->stream->write_function(cb->stream, "        <mwi-account>%s@%s</mwi-account>\n", switch_str_nil(argv[16]), switch_str_nil(argv[17]));
2847 	cb->stream->write_function(cb->stream, "    </registration>\n");
2848 
2849 	return 0;
2850 }
2851 
sql2str_callback(void * pArg,int argc,char ** argv,char ** columnNames)2852 static int sql2str_callback(void *pArg, int argc, char **argv, char **columnNames)
2853 {
2854 	struct cb_helper_sql2str *cbt = (struct cb_helper_sql2str *) pArg;
2855 
2856 	switch_copy_string(cbt->buf, argv[0], cbt->len);
2857 	cbt->matches++;
2858 	return 0;
2859 }
2860 
sofia_profile_reg_count(sofia_profile_t * profile)2861 uint32_t sofia_profile_reg_count(sofia_profile_t *profile)
2862 {
2863 	struct cb_helper_sql2str cb;
2864 	char reg_count[80] = "";
2865 	char *sql;
2866 	cb.buf = reg_count;
2867 	cb.len = sizeof(reg_count);
2868 	sql = switch_mprintf("select count(*) from sip_registrations where profile_name = '%q'", profile->name);
2869 	sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sql2str_callback, &cb);
2870 	free(sql);
2871 	return strtoul(reg_count, NULL, 10);
2872 }
2873 
2874 static const char *status_names[] = { "DOWN", "UP", NULL };
2875 
cmd_status(char ** argv,int argc,switch_stream_handle_t * stream)2876 static switch_status_t cmd_status(char **argv, int argc, switch_stream_handle_t *stream)
2877 {
2878 	sofia_profile_t *profile = NULL;
2879 	sofia_gateway_t *gp;
2880 	switch_hash_index_t *hi;
2881 	void *val;
2882 	const void *vvar;
2883 	int c = 0;
2884 	int ac = 0;
2885 	const char *line = "=================================================================================================";
2886 
2887 	if (argc > 0) {
2888 		if (argc == 1) {
2889 			/* show summary of all gateways */
2890 
2891 			uint32_t ib_failed = 0;
2892 			uint32_t ib = 0;
2893 			uint32_t ob_failed = 0;
2894 			uint32_t ob = 0;
2895 
2896 			stream->write_function(stream, "%25s\t%32s\t%s\t%9s\t%s\t%s\n", "Profile::Gateway-Name", "    Data    ", "State", "Ping Time", "IB Calls(F/T)", "OB Calls(F/T)");
2897 			stream->write_function(stream, "%s\n", line);
2898 			switch_mutex_lock(mod_sofia_globals.hash_mutex);
2899 			for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2900 				switch_core_hash_this(hi, &vvar, NULL, &val);
2901 				profile = (sofia_profile_t *) val;
2902 				if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
2903 
2904 					if (!strcmp(vvar, profile->name)) {	/* not an alias */
2905 						for (gp = profile->gateways; gp; gp = gp->next) {
2906 							char *pkey = switch_mprintf("%s::%s", profile->name, gp->name);
2907 
2908 							switch_assert(gp->state < REG_STATE_LAST);
2909 
2910 							c++;
2911 							ib_failed += gp->ib_failed_calls;
2912 							ib += gp->ib_calls;
2913 							ob_failed += gp->ob_failed_calls;
2914 							ob += gp->ob_calls;
2915 
2916 							stream->write_function(stream, "%25s\t%32s\t%s\t%6.2f\t%u/%u\t%u/%u",
2917 												   pkey, gp->register_to, sofia_state_names[gp->state], gp->ping_time,
2918 												   gp->ib_failed_calls, gp->ib_calls, gp->ob_failed_calls, gp->ob_calls);
2919 							free(pkey);
2920 
2921 							if (gp->state == REG_STATE_FAILED || gp->state == REG_STATE_TRYING) {
2922 								time_t now = switch_epoch_time_now(NULL);
2923 								if (gp->reg_timeout > now) {
2924 									stream->write_function(stream, " (retry: %ds)", gp->reg_timeout - now);
2925 								} else {
2926 									stream->write_function(stream, " (retry: NEVER)");
2927 								}
2928 							}
2929 							stream->write_function(stream, "\n");
2930 						}
2931 					}
2932 				}
2933 			}
2934 			switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2935 			stream->write_function(stream, "%s\n", line);
2936 			stream->write_function(stream, "%d gateway%s: Inbound(Failed/Total): %u/%u,"
2937 								   "Outbound(Failed/Total):%u/%u\n", c, c == 1 ? "" : "s", ib_failed, ib, ob_failed, ob);
2938 
2939 			return SWITCH_STATUS_SUCCESS;
2940 		}
2941 
2942 		if (!strcasecmp(argv[0], "gateway")) {
2943 			if ((gp = sofia_reg_find_gateway(argv[1]))) {
2944 				switch_assert(gp->state < REG_STATE_LAST);
2945 
2946 				stream->write_function(stream, "%s\n", line);
2947 				stream->write_function(stream, "Name    \t%s\n", switch_str_nil(gp->name));
2948 				stream->write_function(stream, "Profile \t%s\n", gp->profile->name);
2949 				stream->write_function(stream, "Scheme  \t%s\n", switch_str_nil(gp->register_scheme));
2950 				stream->write_function(stream, "Realm   \t%s\n", switch_str_nil(gp->register_realm));
2951 				stream->write_function(stream, "Username\t%s\n", switch_str_nil(gp->register_username));
2952 				stream->write_function(stream, "Password\t%s\n", zstr(gp->register_password) ? "no" : "yes");
2953 				stream->write_function(stream, "From    \t%s\n", switch_str_nil(gp->register_from));
2954 				stream->write_function(stream, "Contact \t%s\n", switch_str_nil(gp->register_contact));
2955 				stream->write_function(stream, "Exten   \t%s\n", switch_str_nil(gp->extension));
2956 				stream->write_function(stream, "To      \t%s\n", switch_str_nil(gp->register_to));
2957 				stream->write_function(stream, "Proxy   \t%s\n", switch_str_nil(gp->register_proxy));
2958 				stream->write_function(stream, "Context \t%s\n", switch_str_nil(gp->register_context));
2959 				stream->write_function(stream, "Expires \t%s\n", switch_str_nil(gp->expires_str));
2960 				stream->write_function(stream, "Freq    \t%d\n", gp->freq);
2961 				stream->write_function(stream, "Ping    \t%d\n", gp->ping);
2962 				stream->write_function(stream, "PingFreq\t%d\n", gp->ping_freq);
2963 				stream->write_function(stream, "PingTime\t%0.2f\n", gp->ping_time);
2964 				stream->write_function(stream, "PingState\t%d/%d/%d\n", gp->ping_min, gp->ping_count, gp->ping_max);
2965 				stream->write_function(stream, "State   \t%s\n", sofia_state_names[gp->state]);
2966 				stream->write_function(stream, "Status  \t%s%s\n", status_names[gp->status], gp->pinging ? " (ping)" : "");
2967 				stream->write_function(stream, "Uptime  \t%lds\n", gp->status == SOFIA_GATEWAY_UP ? (switch_time_now()-gp->uptime)/1000000 : 0);
2968 				stream->write_function(stream, "CallsIN \t%u\n", gp->ib_calls);
2969 				stream->write_function(stream, "CallsOUT\t%u\n", gp->ob_calls);
2970 				stream->write_function(stream, "FailedCallsIN\t%u\n", gp->ib_failed_calls);
2971 				stream->write_function(stream, "FailedCallsOUT\t%u\n", gp->ob_failed_calls);
2972 				stream->write_function(stream, "%s\n", line);
2973 				sofia_reg_release_gateway(gp);
2974 			} else {
2975 				stream->write_function(stream, "Invalid Gateway!\n");
2976 			}
2977 		} else if (!strcasecmp(argv[0], "profile")) {
2978 			struct cb_helper cb;
2979 			char *sql = NULL;
2980 			uint32_t x = 0;
2981 
2982 			cb.row_process = 0;
2983 
2984 
2985 			if ((argv[1]) && (profile = sofia_glue_find_profile(argv[1]))) {
2986 				if (!argv[2] || (strcasecmp(argv[2], "reg") && strcasecmp(argv[2], "user"))) {
2987 					stream->write_function(stream, "%s\n", line);
2988 					stream->write_function(stream, "Name             \t%s\n", switch_str_nil(argv[1]));
2989 					stream->write_function(stream, "Domain Name      \t%s\n", profile->domain_name ? profile->domain_name : "N/A");
2990 					if (strcasecmp(argv[1], profile->name)) {
2991 						stream->write_function(stream, "Alias Of         \t%s\n", switch_str_nil(profile->name));
2992 					}
2993 					stream->write_function(stream, "Auto-NAT         \t%s\n", sofia_test_pflag(profile, PFLAG_AUTO_NAT) ? "true" : "false");
2994 					stream->write_function(stream, "DBName           \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn));
2995 					stream->write_function(stream, "Pres Hosts       \t%s\n", switch_str_nil(profile->presence_hosts));
2996 					stream->write_function(stream, "Dialplan         \t%s\n", switch_str_nil(profile->dialplan));
2997 					stream->write_function(stream, "Context          \t%s\n", switch_str_nil(profile->context));
2998 					stream->write_function(stream, "Challenge Realm  \t%s\n", zstr(profile->challenge_realm) ? "auto_to" : profile->challenge_realm);
2999 
3000 					for (x = 0; x < profile->rtpip_index; x++) {
3001 						stream->write_function(stream, "RTP-IP           \t%s\n", switch_str_nil(profile->rtpip[x]));
3002 					}
3003 
3004 					for (x = 0; x < profile->rtpip_index6; x++) {
3005 						stream->write_function(stream, "RTP-IP           \t%s\n", switch_str_nil(profile->rtpip6[x]));
3006 					}
3007 
3008 					if (profile->extrtpip) {
3009 						stream->write_function(stream, "Ext-RTP-IP       \t%s\n", profile->extrtpip);
3010 					}
3011 
3012 					stream->write_function(stream, "SIP-IP           \t%s\n", switch_str_nil(profile->sipip));
3013 					if (profile->extsipip) {
3014 						stream->write_function(stream, "Ext-SIP-IP       \t%s\n", profile->extsipip);
3015 					}
3016 					if (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only) {
3017 						stream->write_function(stream, "URL              \t%s\n", switch_str_nil(profile->url));
3018 						stream->write_function(stream, "BIND-URL         \t%s\n", switch_str_nil(profile->bindurl));
3019 					}
3020 					if (sofia_test_pflag(profile, PFLAG_TLS)) {
3021 						stream->write_function(stream, "TLS-URL          \t%s\n", switch_str_nil(profile->tls_url));
3022 						stream->write_function(stream, "TLS-BIND-URL     \t%s\n", switch_str_nil(profile->tls_bindurl));
3023 					}
3024 					if (profile->ws_bindurl) {
3025 						stream->write_function(stream, "WS-BIND-URL     \t%s\n", switch_str_nil(profile->ws_bindurl));
3026 					}
3027 					if (profile->wss_bindurl) {
3028 						stream->write_function(stream, "WSS-BIND-URL     \t%s\n", switch_str_nil(profile->wss_bindurl));
3029 					}
3030 					stream->write_function(stream, "HOLD-MUSIC       \t%s\n", zstr(profile->hold_music) ? "N/A" : profile->hold_music);
3031 					stream->write_function(stream, "OUTBOUND-PROXY   \t%s\n", zstr(profile->outbound_proxy) ? "N/A" : profile->outbound_proxy);
3032 					stream->write_function(stream, "CODECS IN        \t%s\n", switch_str_nil(profile->inbound_codec_string));
3033 					stream->write_function(stream, "CODECS OUT       \t%s\n", switch_str_nil(profile->outbound_codec_string));
3034 
3035 					stream->write_function(stream, "TEL-EVENT        \t%d\n", profile->te);
3036 					if (profile->dtmf_type == DTMF_2833) {
3037 						stream->write_function(stream, "DTMF-MODE        \trfc2833\n");
3038 					} else if (profile->dtmf_type == DTMF_INFO) {
3039 						stream->write_function(stream, "DTMF-MODE        \tinfo\n");
3040 					} else {
3041 						stream->write_function(stream, "DTMF-MODE        \tnone\n");
3042 					}
3043 					stream->write_function(stream, "CNG              \t%d\n", profile->cng_pt);
3044 					stream->write_function(stream, "SESSION-TO       \t%d\n", profile->session_timeout);
3045 					stream->write_function(stream, "MAX-DIALOG       \t%d\n", profile->max_proceeding);
3046 					stream->write_function(stream, "NOMEDIA          \t%s\n", sofia_test_flag(profile, TFLAG_INB_NOMEDIA) ? "true" : "false");
3047 					stream->write_function(stream, "LATE-NEG         \t%s\n", sofia_test_flag(profile, TFLAG_LATE_NEGOTIATION) ? "true" : "false");
3048 					stream->write_function(stream, "PROXY-MEDIA      \t%s\n", sofia_test_flag(profile, TFLAG_PROXY_MEDIA) ? "true" : "false");
3049 					stream->write_function(stream, "ZRTP-PASSTHRU    \t%s\n", sofia_test_flag(profile, TFLAG_ZRTP_PASSTHRU) ? "true" : "false");
3050 					stream->write_function(stream, "AGGRESSIVENAT    \t%s\n",
3051 										   sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? "true" : "false");
3052 					if (profile->user_agent_filter) {
3053 						stream->write_function(stream, "USER-AGENT-FILTER\t%s\n", switch_str_nil(profile->user_agent_filter));
3054 					}
3055 					if (profile->max_registrations_perext > 0) {
3056 						stream->write_function(stream, "MAX-REG-PEREXT   \t%d\n", profile->max_registrations_perext);
3057 					}
3058 					stream->write_function(stream, "CALLS-IN         \t%u\n", profile->ib_calls);
3059 					stream->write_function(stream, "FAILED-CALLS-IN  \t%u\n", profile->ib_failed_calls);
3060 					stream->write_function(stream, "CALLS-OUT        \t%u\n", profile->ob_calls);
3061 					stream->write_function(stream, "FAILED-CALLS-OUT \t%u\n", profile->ob_failed_calls);
3062 					stream->write_function(stream, "REGISTRATIONS    \t%lu\n", sofia_profile_reg_count(profile));
3063 				}
3064 
3065 				cb.profile = profile;
3066 				cb.stream = stream;
3067 
3068 				if (argv[2] && !strcasecmp(argv[2], "pres") && argv[3]) {
3069 					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
3070 										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
3071 										 "network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status,ping_time"
3072 										 " from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'", profile->name, argv[3]);
3073 				}
3074 				if (!sql && argv[2] && !strcasecmp(argv[2], "reg") && argv[3]) {
3075 					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
3076 										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
3077 										 "network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host, ping_status,ping_time"
3078 										 " from sip_registrations where profile_name='%q' and contact like '%%%q%%'", profile->name, argv[3]);
3079 				}
3080 				if (!sql && argv[2] && !strcasecmp(argv[2], "reg")) {
3081 					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
3082 										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
3083 										 "network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status,ping_time"
3084 										 " from sip_registrations where profile_name='%q'", profile->name);
3085 				}
3086 				if (!sql && argv[2] && !strcasecmp(argv[2], "user") && argv[3]) {
3087 					char *dup = strdup(argv[3]);
3088 					char *host = NULL, *user = NULL;
3089 					char *sqlextra = NULL;
3090 
3091 					switch_assert(dup);
3092 
3093 					if ((host = strchr(dup, '@'))) {
3094 						*host++ = '\0';
3095 						user = dup;
3096 					} else {
3097 						host = dup;
3098 					}
3099 
3100 					if (zstr(user)) {
3101 						sqlextra = switch_mprintf("(sip_host='%q')", host);
3102 					} else if (zstr(host)) {
3103 						sqlextra = switch_mprintf("(sip_user='%q')", user);
3104 					} else {
3105 						sqlextra = switch_mprintf("(sip_user='%q' and sip_host='%q')", user, host);
3106 					}
3107 
3108 					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
3109 										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
3110 										 "network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status,ping_time"
3111 										 " from sip_registrations where profile_name='%q' and %s", profile->name, sqlextra);
3112 					switch_safe_free(dup);
3113 					switch_safe_free(sqlextra);
3114 				}
3115 
3116 				if (sql) {
3117 					stream->write_function(stream, "\nRegistrations:\n%s\n", line);
3118 
3119 					sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, show_reg_callback, &cb);
3120 					switch_safe_free(sql);
3121 
3122 					stream->write_function(stream, "Total items returned: %d\n", cb.row_process);
3123 					stream->write_function(stream, "%s\n", line);
3124 				}
3125 
3126 				sofia_glue_release_profile(profile);
3127 
3128 			} else {
3129 				stream->write_function(stream, "Invalid Profile!\n");
3130 			}
3131 		} else {
3132 			stream->write_function(stream, "Invalid Syntax!\n");
3133 		}
3134 
3135 		return SWITCH_STATUS_SUCCESS;
3136 	}
3137 
3138 	stream->write_function(stream, "%25s\t%s\t  %40s\t%s\n", "Name", "   Type", "Data", "State");
3139 	stream->write_function(stream, "%s\n", line);
3140 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
3141 	for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
3142 		switch_core_hash_this(hi, &vvar, NULL, &val);
3143 		profile = (sofia_profile_t *) val;
3144 		if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
3145 
3146 			if (strcmp(vvar, profile->name)) {
3147 				ac++;
3148 				stream->write_function(stream, "%25s\t%s\t  %40s\t%s\n", vvar, "  alias", profile->name, "ALIASED");
3149 			} else {
3150 				if (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only) {
3151 					stream->write_function(stream, "%25s\t%s\t  %40s\t%s (%u)\n", profile->name, "profile", profile->url,
3152 									   sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN", profile->inuse);
3153 				}
3154 
3155 				if (sofia_test_pflag(profile, PFLAG_TLS)) {
3156 					stream->write_function(stream, "%25s\t%s\t  %40s\t%s (%u) (TLS)\n", profile->name, "profile", profile->tls_url,
3157 										   sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN", profile->inuse);
3158 				}
3159 
3160 				c++;
3161 
3162 				for (gp = profile->gateways; gp; gp = gp->next) {
3163 					char *pkey = switch_mprintf("%s::%s", profile->name, gp->name);
3164 
3165 					switch_assert(gp->state < REG_STATE_LAST);
3166 
3167 					stream->write_function(stream, "%25s\t%s\t  %40s\t%s", pkey, "gateway", gp->register_to, sofia_state_names[gp->state]);
3168 					free(pkey);
3169 
3170 					if (gp->state == REG_STATE_FAILED || gp->state == REG_STATE_TRYING) {
3171 						time_t now = switch_epoch_time_now(NULL);
3172 						if (gp->retry > now) {
3173 							stream->write_function(stream, " (retry: %ds)", gp->retry - now);
3174 						} else {
3175 							stream->write_function(stream, " (retry: NEVER)");
3176 						}
3177 					}
3178 					stream->write_function(stream, "\n");
3179 				}
3180 			}
3181 		}
3182 	}
3183 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
3184 	stream->write_function(stream, "%s\n", line);
3185 	stream->write_function(stream, "%d profile%s %d alias%s\n", c, c == 1 ? "" : "s", ac, ac == 1 ? "" : "es");
3186 	return SWITCH_STATUS_SUCCESS;
3187 }
3188 
xml_gateway_status(sofia_gateway_t * gp,switch_stream_handle_t * stream)3189 static void xml_gateway_status(sofia_gateway_t *gp, switch_stream_handle_t *stream)
3190 {
3191 	char xmlbuf[2096];
3192 	const int buflen = 2096;
3193 
3194 	stream->write_function(stream, "  <gateway>\n");
3195 	stream->write_function(stream, "    <name>%s</name>\n", switch_str_nil(gp->name));
3196 	stream->write_function(stream, "    <profile>%s</profile>\n", gp->profile->name);
3197 	stream->write_function(stream, "    <scheme>%s</scheme>\n", switch_str_nil(gp->register_scheme));
3198 	stream->write_function(stream, "    <realm>%s</realm>\n", switch_str_nil(gp->register_realm));
3199 	stream->write_function(stream, "    <username>%s</username>\n", switch_str_nil(gp->register_username));
3200 	stream->write_function(stream, "    <password>%s</password>\n", zstr(gp->register_password) ? "no" : "yes");
3201 	stream->write_function(stream, "    <from>%s</from>\n", switch_amp_encode(switch_str_nil(gp->register_from), xmlbuf, buflen));
3202 	stream->write_function(stream, "    <contact>%s</contact>\n", switch_amp_encode(switch_str_nil(gp->register_contact), xmlbuf, buflen));
3203 	stream->write_function(stream, "    <exten>%s</exten>\n", switch_amp_encode(switch_str_nil(gp->extension), xmlbuf, buflen));
3204 	stream->write_function(stream, "    <to>%s</to>\n", switch_str_nil(gp->register_to));
3205 	stream->write_function(stream, "    <proxy>%s</proxy>\n", switch_str_nil(gp->register_proxy));
3206 	stream->write_function(stream, "    <context>%s</context>\n", switch_str_nil(gp->register_context));
3207 	stream->write_function(stream, "    <expires>%s</expires>\n", switch_str_nil(gp->expires_str));
3208 	stream->write_function(stream, "    <freq>%d</freq>\n", gp->freq);
3209 	stream->write_function(stream, "    <ping>%d</ping>\n", gp->ping);
3210 	stream->write_function(stream, "    <pingfreq>%d</pingfreq>\n", gp->ping_freq);
3211 	stream->write_function(stream, "    <pingmin>%d</pingmin>\n", gp->ping_min);
3212 	stream->write_function(stream, "    <pingcount>%d</pingcount>\n", gp->ping_count);
3213 	stream->write_function(stream, "    <pingmax>%d</pingmax>\n", gp->ping_max);
3214 	stream->write_function(stream, "    <pingtime>%0.2f</pingtime>\n", gp->ping_time);
3215 	stream->write_function(stream, "    <pinging>%d</pinging>\n", gp->pinging);
3216 	stream->write_function(stream, "    <state>%s</state>\n", sofia_state_names[gp->state]);
3217 	stream->write_function(stream, "    <status>%s</status>\n", status_names[gp->status]);
3218 	stream->write_function(stream, "    <uptime-usec>%ld</uptime-usec>\n", gp->status == SOFIA_GATEWAY_UP ? switch_time_now()-gp->uptime : 0);
3219 	stream->write_function(stream, "    <calls-in>%u</calls-in>\n", gp->ib_calls);
3220 	stream->write_function(stream, "    <calls-out>%u</calls-out>\n", gp->ob_calls);
3221 	stream->write_function(stream, "    <failed-calls-in>%u</failed-calls-in>\n", gp->ib_failed_calls);
3222 	stream->write_function(stream, "    <failed-calls-out>%u</failed-calls-out>\n", gp->ob_failed_calls);
3223 
3224 	if (gp->state == REG_STATE_FAILED || gp->state == REG_STATE_TRYING) {
3225 		time_t now = switch_epoch_time_now(NULL);
3226 		if (gp->retry > now) {
3227 			stream->write_function(stream, "    <retry>%ds</retry>\n", gp->retry - now);
3228 		} else {
3229 			stream->write_function(stream, "    <retry>NEVER</retry>\n");
3230 		}
3231 	}
3232 
3233 	stream->write_function(stream, "  </gateway>\n");
3234 }
3235 
cmd_xml_status(char ** argv,int argc,switch_stream_handle_t * stream)3236 static switch_status_t cmd_xml_status(char **argv, int argc, switch_stream_handle_t *stream)
3237 {
3238 	sofia_profile_t *profile = NULL;
3239 	sofia_gateway_t *gp;
3240 	switch_hash_index_t *hi;
3241 	void *val;
3242 	const void *vvar;
3243 	int c = 0;
3244 	int ac = 0;
3245 	const char *header = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
3246 
3247 	if (argc > 0) {
3248 		if (argc == 1) {
3249 			/* show summary of all gateways */
3250 
3251 			stream->write_function(stream, "%s\n", header);
3252 			stream->write_function(stream, "<gateways>\n", header);
3253 
3254 			switch_mutex_lock(mod_sofia_globals.hash_mutex);
3255 			for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
3256 				switch_core_hash_this(hi, &vvar, NULL, &val);
3257 				profile = (sofia_profile_t *) val;
3258 				if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
3259 
3260 					if (!strcmp(vvar, profile->name)) {	/* not an alias */
3261 						for (gp = profile->gateways; gp; gp = gp->next) {
3262 							switch_assert(gp->state < REG_STATE_LAST);
3263 
3264 							xml_gateway_status(gp, stream);
3265 						}
3266 					}
3267 				}
3268 			}
3269 			switch_mutex_unlock(mod_sofia_globals.hash_mutex);
3270 			stream->write_function(stream, "</gateways>\n");
3271 		} else if (!strcasecmp(argv[0], "gateway")) {
3272 			if ((gp = sofia_reg_find_gateway(argv[1]))) {
3273 				switch_assert(gp->state < REG_STATE_LAST);
3274 				stream->write_function(stream, "%s\n", header);
3275 				xml_gateway_status(gp, stream);
3276 				sofia_reg_release_gateway(gp);
3277 			} else {
3278 				stream->write_function(stream, "Invalid Gateway!\n");
3279 			}
3280 		} else if (!strcasecmp(argv[0], "profile")) {
3281 			struct cb_helper cb;
3282 			char *sql = NULL;
3283 			uint32_t x = 0;
3284 
3285 			cb.row_process = 0;
3286 
3287 			if ((argv[1]) && (profile = sofia_glue_find_profile(argv[1]))) {
3288 				stream->write_function(stream, "%s\n", header);
3289 				stream->write_function(stream, "<profile>\n");
3290 				if (!argv[2] || (strcasecmp(argv[2], "reg") && strcasecmp(argv[2], "user"))) {
3291 					stream->write_function(stream, "  <profile-info>\n");
3292 					stream->write_function(stream, "    <name>%s</name>\n", switch_str_nil(argv[1]));
3293 					stream->write_function(stream, "    <domain-name>%s</domain-name>\n", profile->domain_name ? profile->domain_name : "N/A");
3294 					if (strcasecmp(argv[1], profile->name)) {
3295 						stream->write_function(stream, "    <alias-of>%s</alias-of>\n", switch_str_nil(profile->name));
3296 					}
3297 					stream->write_function(stream, "    <auto-nat>%s</auto-nat>\n", sofia_test_pflag(profile, PFLAG_AUTO_NAT) ? "true" : "false");
3298 					stream->write_function(stream, "    <db-name>%s</db-name>\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn));
3299 					stream->write_function(stream, "    <pres-hosts>%s</pres-hosts>\n", switch_str_nil(profile->presence_hosts));
3300 					stream->write_function(stream, "    <dialplan>%s</dialplan>\n", switch_str_nil(profile->dialplan));
3301 					stream->write_function(stream, "    <context>%s</context>\n", switch_str_nil(profile->context));
3302 					stream->write_function(stream, "    <challenge-realm>%s</challenge-realm>\n",
3303 										   zstr(profile->challenge_realm) ? "auto_to" : profile->challenge_realm);
3304 					for (x = 0; x < profile->rtpip_index; x++) {
3305 						stream->write_function(stream, "    <rtp-ip>%s</rtp-ip>\n", switch_str_nil(profile->rtpip[x]));
3306 					}
3307 					for (x = 0; x < profile->rtpip_index6; x++) {
3308 						stream->write_function(stream, "    <rtp-ip>%s</rtp-ip>\n", switch_str_nil(profile->rtpip6[x]));
3309 					}
3310 					if (profile->extrtpip) {
3311 						stream->write_function(stream, "    <ext-rtp-ip>%s</ext-rtp-ip>\n", profile->extrtpip);
3312 					}
3313 					stream->write_function(stream, "    <sip-ip>%s</sip-ip>\n", switch_str_nil(profile->sipip));
3314 					if (profile->extsipip) {
3315 						stream->write_function(stream, "    <ext-sip-ip>%s</ext-sip-ip>\n", profile->extsipip);
3316 					}
3317 					if (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only) {
3318 						stream->write_function(stream, "    <url>%s</url>\n", switch_str_nil(profile->url));
3319 						stream->write_function(stream, "    <bind-url>%s</bind-url>\n", switch_str_nil(profile->bindurl));
3320 					}
3321 					if (sofia_test_pflag(profile, PFLAG_TLS)) {
3322 						stream->write_function(stream, "    <tls-url>%s</tls-url>\n", switch_str_nil(profile->tls_url));
3323 						stream->write_function(stream, "    <tls-bind-url>%s</tls-bind-url>\n", switch_str_nil(profile->tls_bindurl));
3324 					}
3325 					if (profile->ws_bindurl) {
3326 						stream->write_function(stream, "    <ws-bind-url>%s</ws-bind-url>\n", switch_str_nil(profile->ws_bindurl));
3327 					}
3328 					if (profile->wss_bindurl) {
3329 						stream->write_function(stream, "    <wss-bind-url>%s</wss-bind-url>\n", switch_str_nil(profile->wss_bindurl));
3330 					}
3331 					stream->write_function(stream, "    <hold-music>%s</hold-music>\n", zstr(profile->hold_music) ? "N/A" : profile->hold_music);
3332 					stream->write_function(stream, "    <outbound-proxy>%s</outbound-proxy>\n",
3333 										   zstr(profile->outbound_proxy) ? "N/A" : profile->outbound_proxy);
3334 					stream->write_function(stream, "    <inbound-codecs>%s</inbound-codecs>\n", switch_str_nil(profile->inbound_codec_string));
3335 					stream->write_function(stream, "    <outbound-codecs>%s</outbound-codecs>\n", switch_str_nil(profile->outbound_codec_string));
3336 
3337 					stream->write_function(stream, "    <tel-event>%d</tel-event>\n", profile->te);
3338 					if (profile->dtmf_type == DTMF_2833) {
3339 						stream->write_function(stream, "    <dtmf-mode>rfc2833</dtmf-mode>\n");
3340 					} else if (profile->dtmf_type == DTMF_INFO) {
3341 						stream->write_function(stream, "    <dtmf-mode>info</dtmf-mode>\n");
3342 					} else {
3343 						stream->write_function(stream, "    <dtmf-mode>none</dtmf-mode>\n");
3344 					}
3345 					stream->write_function(stream, "    <cng>%d</cng>\n", profile->cng_pt);
3346 					stream->write_function(stream, "    <session-to>%d</session-to>\n", profile->session_timeout);
3347 					stream->write_function(stream, "    <max-dialog>%d</max-dialog>\n", profile->max_proceeding);
3348 					stream->write_function(stream, "    <nomedia>%s</nomedia>\n", sofia_test_flag(profile, TFLAG_INB_NOMEDIA) ? "true" : "false");
3349 					stream->write_function(stream, "    <late-neg>%s</late-neg>\n", sofia_test_flag(profile, TFLAG_LATE_NEGOTIATION) ? "true" : "false");
3350 					stream->write_function(stream, "    <proxy-media>%s</proxy-media>\n", sofia_test_flag(profile, TFLAG_PROXY_MEDIA) ? "true" : "false");
3351 					stream->write_function(stream, "    <zrtp-passthru>%s</zrtp-passthru>\n", sofia_test_flag(profile, TFLAG_ZRTP_PASSTHRU) ? "true" : "false");
3352 					stream->write_function(stream, "    <aggressive-nat>%s</aggressive-nat>\n",
3353 										   sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION) ? "true" : "false");
3354 					if (profile->user_agent_filter) {
3355 						stream->write_function(stream, "    <user-agent-filter>%s</user-agent-filter>\n", switch_str_nil(profile->user_agent_filter));
3356 					}
3357 					if (profile->max_registrations_perext > 0) {
3358 						stream->write_function(stream, "    <max-registrations-per-extension>%d</max-registrations-per-extension>\n",
3359 										   profile->max_registrations_perext);
3360 					}
3361 					stream->write_function(stream, "    <calls-in>%u</calls-in>\n", profile->ib_calls);
3362 					stream->write_function(stream, "    <calls-out>%u</calls-out>\n", profile->ob_calls);
3363 					stream->write_function(stream, "    <failed-calls-in>%u</failed-calls-in>\n", profile->ib_failed_calls);
3364 					stream->write_function(stream, "    <failed-calls-out>%u</failed-calls-out>\n", profile->ob_failed_calls);
3365 					stream->write_function(stream, "    <registrations>%lu</registrations>\n", sofia_profile_reg_count(profile));
3366 					stream->write_function(stream, "  </profile-info>\n");
3367 				}
3368 
3369 				cb.profile = profile;
3370 				cb.stream = stream;
3371 
3372 				if (argv[2] && !strcasecmp(argv[2], "pres") && argv[3]) {
3373 
3374 					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
3375 										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
3376 										 "network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status,ping_time"
3377 										 " from sip_registrations where profile_name='%q' and presence_hosts like '%%%q%%'", profile->name, argv[3]);
3378 				}
3379 				if (!sql && argv[2] && !strcasecmp(argv[2], "reg") && argv[3]) {
3380 
3381 					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
3382 										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
3383 										 "network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status,ping_time"
3384 										 " from sip_registrations where profile_name='%q' and contact like '%%%q%%'", profile->name, argv[3]);
3385 				}
3386 				if (!sql && argv[2] && !strcasecmp(argv[2], "reg")) {
3387 
3388 					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
3389 										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
3390 										 "network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status,ping_time"
3391 										 " from sip_registrations where profile_name='%q'", profile->name);
3392 				}
3393 				if (!sql && argv[2] && !strcasecmp(argv[2], "user") && argv[3]) {
3394 					char *dup = strdup(argv[3]);
3395 					char *host = NULL, *user = NULL;
3396 					char *sqlextra = NULL;
3397 
3398 					switch_assert(dup);
3399 
3400 					if ((host = strchr(dup, '@'))) {
3401 						*host++ = '\0';
3402 						user = dup;
3403 					} else {
3404 						host = dup;
3405 					}
3406 
3407 					if (zstr(user)) {
3408 						sqlextra = switch_mprintf("(sip_host='%q')", host);
3409 					} else if (zstr(host)) {
3410 						sqlextra = switch_mprintf("(sip_user='%q')", user);
3411 					} else {
3412 						sqlextra = switch_mprintf("(sip_user='%q' and sip_host='%q')", user, host);
3413 					}
3414 
3415 					sql = switch_mprintf("select call_id,sip_user,sip_host,contact,status,"
3416 										 "rpid,expires,user_agent,server_user,server_host,profile_name,hostname,"
3417 										 "network_ip,network_port,sip_username,sip_realm,mwi_user,mwi_host,ping_status,ping_time"
3418 										 " from sip_registrations where profile_name='%q' and %s", profile->name, sqlextra);
3419 					switch_safe_free(dup);
3420 					switch_safe_free(sqlextra);
3421 				}
3422 
3423 				if (sql) {
3424 					stream->write_function(stream, "  <registrations>\n");
3425 
3426 					sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, show_reg_callback_xml, &cb);
3427 					switch_safe_free(sql);
3428 
3429 					stream->write_function(stream, "  </registrations>\n");
3430 				}
3431 
3432 				stream->write_function(stream, "</profile>\n");
3433 
3434 				sofia_glue_release_profile(profile);
3435 			} else {
3436 				stream->write_function(stream, "Invalid Profile!\n");
3437 			}
3438 		} else {
3439 			stream->write_function(stream, "Invalid Syntax!\n");
3440 		}
3441 
3442 		return SWITCH_STATUS_SUCCESS;
3443 	}
3444 
3445 	stream->write_function(stream, "%s\n", header);
3446 	stream->write_function(stream, "<profiles>\n");
3447 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
3448 	for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
3449 		switch_core_hash_this(hi, &vvar, NULL, &val);
3450 		profile = (sofia_profile_t *) val;
3451 		if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
3452 
3453 			if (strcmp(vvar, profile->name)) {
3454 				ac++;
3455 				stream->write_function(stream, "<alias>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s</state>\n</alias>\n", vvar, "alias",
3456 									   profile->name, "ALIASED");
3457 			} else {
3458 				if (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only){
3459 					stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%u)</state>\n</profile>\n",
3460 									   profile->name, "profile", profile->url, sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN",
3461 									   profile->inuse);
3462 				}
3463 
3464 				if (sofia_test_pflag(profile, PFLAG_TLS)) {
3465 					stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%u) (TLS)</state>\n</profile>\n",
3466 									   profile->name, "profile", profile->tls_url, sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN",
3467 									   profile->inuse);
3468 				}
3469 				if (profile->ws_bindurl){
3470 					stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%u) (WS)</state>\n</profile>\n",
3471 									   profile->name, "profile", profile->ws_bindurl, sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN",
3472 									   profile->inuse);
3473 				}
3474 				if (profile->wss_bindurl){
3475 					stream->write_function(stream, "<profile>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s (%u) (WSS)</state>\n</profile>\n",
3476 									   profile->name, "profile", profile->wss_bindurl, sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN",
3477 									   profile->inuse);
3478 				}
3479 
3480 				c++;
3481 
3482 				for (gp = profile->gateways; gp; gp = gp->next) {
3483 					switch_assert(gp->state < REG_STATE_LAST);
3484 					stream->write_function(stream, "<gateway>\n<name>%s</name>\n<type>%s</type>\n<data>%s</data>\n<state>%s</state>\n</gateway>\n",
3485 										   gp->name, "gateway", gp->register_to, sofia_state_names[gp->state]);
3486 					if (gp->state == REG_STATE_FAILED || gp->state == REG_STATE_TRYING) {
3487 						time_t now = switch_epoch_time_now(NULL);
3488 						if (gp->retry > now) {
3489 							stream->write_function(stream, " (retry: %ds)", gp->retry - now);
3490 						} else {
3491 							stream->write_function(stream, " (retry: NEVER)");
3492 						}
3493 					}
3494 					stream->write_function(stream, "\n");
3495 				}
3496 			}
3497 		}
3498 	}
3499 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
3500 	stream->write_function(stream, "</profiles>\n");
3501 	return SWITCH_STATUS_SUCCESS;
3502 }
3503 
cmd_profile(char ** argv,int argc,switch_stream_handle_t * stream)3504 static switch_status_t cmd_profile(char **argv, int argc, switch_stream_handle_t *stream)
3505 {
3506 	sofia_profile_t *profile = NULL;
3507 	char *profile_name = argv[0];
3508 	const char *err;
3509 
3510 	if (argc < 2) {
3511 		stream->write_function(stream, "Invalid Args!\n");
3512 		return SWITCH_STATUS_SUCCESS;
3513 	}
3514 
3515 	if (!strcasecmp(argv[1], "start")) {
3516 
3517 		switch_xml_reload(&err);
3518 		stream->write_function(stream, "Reload XML [%s]\n", err);
3519 
3520 		if (config_sofia(SOFIA_CONFIG_RESCAN, argv[0]) == SWITCH_STATUS_SUCCESS) {
3521 			stream->write_function(stream, "%s started successfully\n", argv[0]);
3522 		} else {
3523 			stream->write_function(stream, "Failure starting %s\n", argv[0]);
3524 		}
3525 		return SWITCH_STATUS_SUCCESS;
3526 	}
3527 
3528 	if (argv[1] && !strcasecmp(argv[0], "restart") && !strcasecmp(argv[1], "all")) {
3529 		sofia_glue_restart_all_profiles();
3530 		return SWITCH_STATUS_SUCCESS;
3531 	}
3532 
3533 	if (zstr(profile_name) || !(profile = sofia_glue_find_profile(profile_name))) {
3534 		stream->write_function(stream, "Invalid Profile [%s]", switch_str_nil(profile_name));
3535 		return SWITCH_STATUS_SUCCESS;
3536 	}
3537 
3538 	if (!strcasecmp(argv[1], "killgw")) {
3539 		sofia_gateway_t *gateway_ptr;
3540 		if (argc < 3) {
3541 			stream->write_function(stream, "-ERR missing gw name\n");
3542 			goto done;
3543 		}
3544 
3545 		if (!strcasecmp(argv[2], "_all_")) {
3546 			sofia_glue_del_every_gateway(profile);
3547 			stream->write_function(stream, "+OK every gateway marked for deletion.\n");
3548 		} else {
3549 			if ((gateway_ptr = sofia_reg_find_gateway(argv[2]))) {
3550 				sofia_glue_del_gateway(gateway_ptr);
3551 				sofia_reg_release_gateway(gateway_ptr);
3552 				stream->write_function(stream, "+OK gateway marked for deletion.\n");
3553 			} else {
3554 				stream->write_function(stream, "-ERR no such gateway.\n");
3555 			}
3556 		}
3557 
3558 		goto done;
3559 	} else if (!strcasecmp(argv[1], "startgw")) {
3560 		if (argc < 3) {
3561 			stream->write_function(stream, "-ERR missing gw name\n");
3562 			goto done;
3563 		}
3564 
3565 		switch_xml_reload(&err);
3566 		stream->write_function(stream, "Reload XML [%s]\n", err);
3567 
3568 		if (config_gateway(profile->name, argv[2]) == SWITCH_STATUS_SUCCESS) {
3569 			stream->write_function(stream, "+OK start gateway %s complete\n", argv[2]);
3570 		} else {
3571 			stream->write_function(stream, "-ERR cannot add gateway %s for profile %s\n", argv[2], profile->name);
3572 		}
3573 
3574 		goto done;
3575 	}
3576 
3577 	if (!strcasecmp(argv[1], "rescan")) {
3578 
3579 		switch_xml_reload(&err);
3580 		stream->write_function(stream, "Reload XML [%s]\n", err);
3581 
3582 		if (config_sofia(SOFIA_CONFIG_RESCAN, profile->name) == SWITCH_STATUS_SUCCESS) {
3583 			stream->write_function(stream, "+OK scan complete\n");
3584 		} else {
3585 			stream->write_function(stream, "-ERR cannot find config for profile %s\n", profile->name);
3586 		}
3587 		goto done;
3588 	}
3589 
3590 	if (!strcasecmp(argv[1], "check_sync")) {
3591 		if (argc > 2) {
3592 			sofia_reg_check_call_id(profile, argv[2]);
3593 			stream->write_function(stream, "+OK syncing all registrations matching specified call_id\n");
3594 		} else {
3595 			sofia_reg_check_sync(profile);
3596 			stream->write_function(stream, "+OK syncing all registrations\n");
3597 		}
3598 
3599 		goto done;
3600 	}
3601 
3602 
3603 	if (!strcasecmp(argv[1], "flush_inbound_reg")) {
3604 		int reboot = 0;
3605 
3606 		if (argc > 2) {
3607 			if (!strcasecmp(argv[2], "reboot")) {
3608 				reboot = 1;
3609 				argc = 2;
3610 			}
3611 		}
3612 
3613 		if (argc > 2) {
3614 			if (argc > 3 && !strcasecmp(argv[3], "reboot")) {
3615 				reboot = 1;
3616 			}
3617 
3618 			sofia_reg_expire_call_id(profile, argv[2], reboot);
3619 			stream->write_function(stream, "+OK %s all registrations matching specified call_id\n", reboot ? "rebooting" : "flushing");
3620 		} else {
3621 			sofia_reg_check_expire(profile, 0, reboot);
3622 			stream->write_function(stream, "+OK %s all registrations\n", reboot ? "rebooting" : "flushing");
3623 		}
3624 
3625 		goto done;
3626 	}
3627 
3628 	if (!strcasecmp(argv[1], "recover")) {
3629 		if (argv[2] && !strcasecmp(argv[2], "flush")) {
3630 			sofia_glue_profile_recover(profile, SWITCH_TRUE);
3631 
3632 			stream->write_function(stream, "Flushing recovery database.\n");
3633 		} else {
3634 			int x = sofia_glue_profile_recover(profile, SWITCH_FALSE);
3635 			if (x) {
3636 				stream->write_function(stream, "Recovered %d session(s)\n", x);
3637 			} else {
3638 				stream->write_function(stream, "No sessions to recover.\n");
3639 			}
3640 		}
3641 
3642 		goto done;
3643 	}
3644 
3645 	if (!strcasecmp(argv[1], "register")) {
3646 		char *gname = argv[2];
3647 		sofia_gateway_t *gateway_ptr;
3648 
3649 		if (zstr(gname)) {
3650 			stream->write_function(stream, "No gateway name provided!\n");
3651 			goto done;
3652 		}
3653 
3654 		if (!strcasecmp(gname, "all")) {
3655 			for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
3656 				gateway_ptr->retry = 0;
3657 				gateway_ptr->state = REG_STATE_UNREGED;
3658 			}
3659 			stream->write_function(stream, "+OK\n");
3660 		} else if ((gateway_ptr = sofia_reg_find_gateway(gname))) {
3661 			gateway_ptr->retry = 0;
3662 			gateway_ptr->state = REG_STATE_UNREGED;
3663 			stream->write_function(stream, "+OK\n");
3664 			sofia_reg_release_gateway(gateway_ptr);
3665 		} else {
3666 			stream->write_function(stream, "Invalid gateway!\n");
3667 		}
3668 
3669 		goto done;
3670 	}
3671 
3672 	if (!strcasecmp(argv[1], "unregister")) {
3673 		char *gname = argv[2];
3674 		sofia_gateway_t *gateway_ptr;
3675 
3676 		if (zstr(gname)) {
3677 			stream->write_function(stream, "No gateway name provided!\n");
3678 			goto done;
3679 		}
3680 
3681 		if (!strcasecmp(gname, "all")) {
3682 			for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
3683 				gateway_ptr->retry = 0;
3684 				gateway_ptr->state = REG_STATE_UNREGISTER;
3685 			}
3686 			stream->write_function(stream, "+OK\n");
3687 		} else if ((gateway_ptr = sofia_reg_find_gateway(gname))) {
3688 			gateway_ptr->retry = 0;
3689 			gateway_ptr->state = REG_STATE_UNREGISTER;
3690 			stream->write_function(stream, "+OK\n");
3691 			sofia_reg_release_gateway(gateway_ptr);
3692 		} else {
3693 			stream->write_function(stream, "Invalid gateway!\n");
3694 		}
3695 		goto done;
3696 	}
3697 
3698 	if (!strcasecmp(argv[1], "stop") || !strcasecmp(argv[1], "restart")) {
3699 		int rsec = 10;
3700 		int diff = (int) (switch_epoch_time_now(NULL) - profile->started);
3701 		int remain = rsec - diff;
3702 		if (diff < rsec) {
3703 			stream->write_function(stream, "Profile %s must be up for at least %d seconds to stop/restart.\nPlease wait %d second%s\n",
3704 								   profile->name, rsec, remain, remain == 1 ? "" : "s");
3705 		} else {
3706 
3707 			switch_xml_reload(&err);
3708 			stream->write_function(stream, "Reload XML [%s]\n", err);
3709 
3710 			if (!strcasecmp(argv[1], "stop")) {
3711 				sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
3712 				if (argv[2] && !strcasecmp(argv[2], "wait")) {
3713 					int loops = 20 * 2;
3714 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Waiting for %s to finish SIP transactions.\n", profile->name);
3715 					while (!sofia_test_pflag(profile, PFLAG_SHUTDOWN)) {
3716 						switch_yield(500000);
3717 						if (!--loops) {
3718 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Timeout Waiting for %s to finish SIP transactions.\n", profile->name);
3719 							break;
3720 						}
3721 					}
3722 				}
3723 				stream->write_function(stream, "stopping: %s", profile->name);
3724 			} else {
3725 				sofia_set_pflag_locked(profile, PFLAG_RESPAWN);
3726 				sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
3727 				stream->write_function(stream, "restarting: %s", profile->name);
3728 			}
3729 		}
3730 		goto done;
3731 	}
3732 
3733 	if (!strcasecmp(argv[1], "siptrace")) {
3734 		if (argc > 2) {
3735 			int value = switch_true(argv[2]);
3736 			nua_set_params(profile->nua, TPTAG_LOG(value), TAG_END());
3737 			stream->write_function(stream, "%s sip debugging on %s", value ? "Enabled" : "Disabled", profile->name);
3738 		} else {
3739 			stream->write_function(stream, "Usage: sofia profile <name> siptrace <on/off>\n");
3740 		}
3741 		goto done;
3742 	}
3743 
3744 	if (!strcasecmp(argv[1], "capture")) {
3745 		if (argc > 2) {
3746 			int value = switch_true(argv[2]);
3747 			nua_set_params(profile->nua, TPTAG_CAPT(value ? mod_sofia_globals.capture_server : NULL), TAG_END());
3748 			stream->write_function(stream, "%s sip capturing on %s", value ? "Enabled" : "Disabled", profile->name);
3749 		} else {
3750 			stream->write_function(stream, "Usage: sofia profile <name> capture <on/off>\n");
3751 		}
3752 		goto done;
3753 	}
3754 
3755 	if (!strcasecmp(argv[1], "watchdog")) {
3756 		if (argc > 2) {
3757 			int value = switch_true(argv[2]);
3758 			profile->watchdog_enabled = value;
3759 			stream->write_function(stream, "%s sip debugging on %s", value ? "Enabled" : "Disabled", profile->name);
3760 		} else {
3761 			stream->write_function(stream, "Usage: sofia profile <name> watchdog <on/off>\n");
3762 		}
3763 		goto done;
3764 	}
3765 
3766 
3767 	if (!strcasecmp(argv[1], "gwlist")) {
3768 		int up = 1;
3769 
3770 		if (argc > 2) {
3771 			if (!strcasecmp(argv[2], "down")) {
3772 				up = 0;
3773 			}
3774 		}
3775 
3776 		sofia_glue_gateway_list(profile, stream, up);
3777 		goto done;
3778 	}
3779 
3780 
3781 	stream->write_function(stream, "-ERR Unknown command!\n");
3782 
3783   done:
3784 	sofia_glue_release_profile(profile);
3785 
3786 	return SWITCH_STATUS_SUCCESS;
3787 }
3788 
contact_callback(void * pArg,int argc,char ** argv,char ** columnNames)3789 static int contact_callback(void *pArg, int argc, char **argv, char **columnNames)
3790 {
3791 	struct cb_helper *cb = (struct cb_helper *) pArg;
3792 	char *contact;
3793 
3794 	cb->row_process++;
3795 
3796 	if (!zstr(argv[0]) && (contact = sofia_glue_get_url_from_contact(argv[0], 1))) {
3797 		if (cb->dedup) {
3798 			char *tmp = switch_mprintf("%ssofia/%s/sip:%s", argv[2], argv[1], sofia_glue_strip_proto(contact));
3799 
3800 			if (!strstr((char *)cb->stream->data, tmp)) {
3801 				cb->stream->write_function(cb->stream, "%s,", tmp);
3802 			}
3803 
3804 			free(tmp);
3805 
3806 		} else {
3807 			cb->stream->write_function(cb->stream, "%ssofia/%s/sip:%s,", argv[2], argv[1], sofia_glue_strip_proto(contact));
3808 		}
3809 		free(contact);
3810 	}
3811 
3812 	return 0;
3813 }
3814 
SWITCH_STANDARD_API(sofia_count_reg_function)3815 SWITCH_STANDARD_API(sofia_count_reg_function)
3816 {
3817 	char *data;
3818 	char *user = NULL;
3819 	char *domain = NULL;
3820 	char *concat = NULL;
3821 	char *profile_name = NULL;
3822 	char *p;
3823 	char *reply = "-1";
3824 	sofia_profile_t *profile = NULL;
3825 
3826 	if (!cmd) {
3827 		stream->write_function(stream, "%s", "");
3828 		return SWITCH_STATUS_SUCCESS;
3829 	}
3830 
3831 	data = strdup(cmd);
3832 	switch_assert(data);
3833 
3834 	if ((p = strchr(data, '/'))) {
3835 		profile_name = data;
3836 		*p++ = '\0';
3837 		user = p;
3838 	} else {
3839 		user = data;
3840 	}
3841 
3842 	if ((domain = strchr(user, '@'))) {
3843 		*domain++ = '\0';
3844 		if ((concat = strchr(domain, '/'))) {
3845 			*concat++ = '\0';
3846 		}
3847 	} else {
3848 		if ((concat = strchr(user, '/'))) {
3849 			*concat++ = '\0';
3850 		}
3851 	}
3852 
3853 	if (!profile_name && domain) {
3854 		profile_name = domain;
3855 	}
3856 
3857 	if (profile_name) {
3858 		char *sql;
3859 
3860 		if (!(profile = sofia_glue_find_profile(profile_name))) {
3861 			profile_name = domain;
3862 			domain = NULL;
3863 		}
3864 
3865 		if (!profile && profile_name) {
3866 			profile = sofia_glue_find_profile(profile_name);
3867 		}
3868 
3869 		if (profile) {
3870 			struct cb_helper_sql2str cb;
3871 			char reg_count[80] = "";
3872 
3873 			cb.buf = reg_count;
3874 			cb.len = sizeof(reg_count);
3875 
3876 			if (!domain || !strchr(domain, '.')) {
3877 				domain = profile->name;
3878 			}
3879 
3880 			if (zstr(user)) {
3881 				sql = switch_mprintf("select count(*) "
3882 									 "from sip_registrations where (sip_host='%q' or presence_hosts like '%%%q%%')",
3883 									 domain, domain);
3884 
3885 			} else {
3886 				sql = switch_mprintf("select count(*) "
3887 									 "from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')",
3888 									 user, domain, domain);
3889 			}
3890 			switch_assert(sql);
3891 			sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sql2str_callback, &cb);
3892 			switch_safe_free(sql);
3893 			if (!zstr(reg_count)) {
3894 				stream->write_function(stream, "%s", reg_count);
3895 			} else {
3896 				stream->write_function(stream, "0");
3897 			}
3898 			reply = NULL;
3899 
3900 		}
3901 	}
3902 
3903 	if (reply) {
3904 		stream->write_function(stream, "%s", reply);
3905 	}
3906 
3907 	switch_safe_free(data);
3908 
3909 	if (profile) {
3910 		sofia_glue_release_profile(profile);
3911 	}
3912 
3913 	return SWITCH_STATUS_SUCCESS;
3914 }
3915 
SWITCH_STANDARD_API(sofia_username_of_function)3916 SWITCH_STANDARD_API(sofia_username_of_function)
3917 {
3918 	char *data;
3919 	char *user = NULL;
3920 	char *domain = NULL;
3921 	char *profile_name = NULL;
3922 	char *p;
3923 	char *reply = "";
3924 	sofia_profile_t *profile = NULL;
3925 
3926 	if (!cmd) {
3927 		stream->write_function(stream, "%s", "");
3928 		return SWITCH_STATUS_SUCCESS;
3929 	}
3930 
3931 	data = strdup(cmd);
3932 	switch_assert(data);
3933 
3934 	if ((p = strchr(data, '/'))) {
3935 		profile_name = data;
3936 		*p++ = '\0';
3937 		user = p;
3938 	} else {
3939 		user = data;
3940 	}
3941 
3942 	if ((domain = strchr(user, '@'))) {
3943 		*domain++ = '\0';
3944 	}
3945 
3946 	if (!profile_name && domain) {
3947 		profile_name = domain;
3948 	}
3949 
3950 	if (profile_name) {
3951 		char *sql;
3952 
3953 		if (!(profile = sofia_glue_find_profile(profile_name))) {
3954 			profile_name = domain;
3955 			domain = NULL;
3956 		}
3957 
3958 		if (!profile && profile_name) {
3959 			profile = sofia_glue_find_profile(profile_name);
3960 		}
3961 
3962 		if (profile) {
3963 			struct cb_helper_sql2str cb;
3964 			char username[256] = "";
3965 
3966 			cb.buf = username;
3967 			cb.len = sizeof(username);
3968 
3969 			if (!domain || !strchr(domain, '.')) {
3970 				domain = profile->name;
3971 			}
3972 
3973 			switch_assert(!zstr(user));
3974 
3975 			sql = switch_mprintf("select sip_username "
3976 									"from sip_registrations where sip_user='%q' and (sip_host='%q' or presence_hosts like '%%%q%%')",
3977 									user, domain, domain);
3978 
3979 			switch_assert(sql);
3980 
3981 			sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, sql2str_callback, &cb);
3982 			switch_safe_free(sql);
3983 			if (!zstr(username)) {
3984 				stream->write_function(stream, "%s", username);
3985 			} else {
3986 				stream->write_function(stream, "");
3987 			}
3988 			reply = NULL;
3989 
3990 		}
3991 	}
3992 
3993 	if (reply) {
3994 		stream->write_function(stream, "%s", reply);
3995 	}
3996 
3997 	switch_safe_free(data);
3998 
3999 	if (profile) {
4000 		sofia_glue_release_profile(profile);
4001 	}
4002 
4003 	return SWITCH_STATUS_SUCCESS;
4004 }
4005 
select_from_profile(sofia_profile_t * profile,const char * user,const char * domain,const char * concat,const char * exclude_contact,const char * match_user_agent,switch_stream_handle_t * stream,switch_bool_t dedup)4006 static void select_from_profile(sofia_profile_t *profile,
4007 								const char *user,
4008 								const char *domain,
4009 								const char *concat,
4010 								const char *exclude_contact,
4011 								const char *match_user_agent,
4012 								switch_stream_handle_t *stream,
4013 								switch_bool_t dedup)
4014 {
4015 	struct cb_helper cb;
4016 	char *sql;
4017 	char *sql_match_user_agent = NULL;
4018 	char *sql_exclude_contact = NULL;
4019 
4020 	cb.row_process = 0;
4021 
4022 	cb.profile = profile;
4023 	cb.stream = stream;
4024 	cb.dedup = dedup;
4025 
4026 	if (match_user_agent) {
4027 		sql_match_user_agent = switch_mprintf(" and user_agent like '%%%q%%'",  match_user_agent);
4028 	}
4029 
4030 	if (exclude_contact) {
4031 		sql_exclude_contact = switch_mprintf(" and contact not like '%%%q%%'",  exclude_contact);
4032 	}
4033 
4034 	sql = switch_mprintf("select contact, profile_name, '%q' "
4035 			"from sip_registrations where profile_name='%q' "
4036 			"and upper(sip_user)=upper('%q') "
4037 			"and (sip_host='%q' or presence_hosts like '%%%q%%')%s%s",
4038 			(concat != NULL) ? concat : "", profile->name, user, domain, domain, (sql_match_user_agent!=NULL) ? sql_match_user_agent : "", (sql_exclude_contact!=NULL) ? sql_exclude_contact : "");
4039 	switch_assert(sql);
4040 	sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, contact_callback, &cb);
4041 	switch_safe_free(sql);
4042 	switch_safe_free(sql_exclude_contact);
4043 	switch_safe_free(sql_match_user_agent);
4044 
4045 }
4046 
SWITCH_STANDARD_API(sofia_contact_function)4047 SWITCH_STANDARD_API(sofia_contact_function)
4048 {
4049 	char *data;
4050 	char *user = NULL;
4051 	char *domain = NULL, *dup_domain = NULL;
4052 	char *concat = NULL;
4053 	char *profile_name = NULL;
4054 	char *p;
4055 
4056 	sofia_profile_t *profile = NULL;
4057 	const char *exclude_contact = NULL;
4058 	const char *match_user_agent = NULL;
4059 	char *reply = "error/facility_not_subscribed";
4060 	switch_stream_handle_t mystream = { 0 };
4061 
4062 	if (!cmd) {
4063 		stream->write_function(stream, "%s", "");
4064 		return SWITCH_STATUS_SUCCESS;
4065 	}
4066 
4067 	if (session) {
4068 		switch_channel_t *channel = switch_core_session_get_channel(session);
4069 		exclude_contact = switch_channel_get_variable(channel, "sip_exclude_contact");
4070 		match_user_agent = switch_channel_get_variable(channel, "sip_match_user_agent");
4071 	}
4072 
4073 
4074 	data = strdup(cmd);
4075 	switch_assert(data);
4076 
4077 	if ((p = strchr(data, '~'))) {
4078 		profile_name = data;
4079 		*p++ = '\0';
4080 		match_user_agent = p;
4081 	}
4082 
4083 	if ((p = strchr(data, '/'))) {
4084 		profile_name = data;
4085 		*p++ = '\0';
4086 		user = p;
4087 	} else {
4088 		user = data;
4089 	}
4090 
4091 	if ((domain = strchr(user, '@'))) {
4092 		*domain++ = '\0';
4093 		if ((concat = strchr(domain, '/'))) {
4094 			*concat++ = '\0';
4095 		}
4096 	} else {
4097 		if ((concat = strchr(user, '/'))) {
4098 			*concat++ = '\0';
4099 		}
4100 	}
4101 
4102 	if (zstr(domain)) {
4103 		dup_domain = switch_core_get_domain(SWITCH_TRUE);
4104 		domain = dup_domain;
4105 	}
4106 
4107 	if (zstr(profile_name) || strcmp(profile_name, "*") || zstr(domain)) {
4108 		if (!zstr(profile_name)) {
4109 			profile = sofia_glue_find_profile(profile_name);
4110 		}
4111 
4112 		if (!profile && !zstr(domain)) {
4113 			profile = sofia_glue_find_profile(domain);
4114 		}
4115 	}
4116 
4117 	if (profile || !zstr(domain)) {
4118 		SWITCH_STANDARD_STREAM(mystream);
4119 		switch_assert(mystream.data);
4120 	}
4121 
4122 	if (profile) {
4123 		if (zstr(domain)) {
4124 			domain = profile->name;
4125 		}
4126 
4127 		if (!zstr(profile->domain_name) && !zstr(profile_name) && !strcmp(profile_name, profile->name)) {
4128 			domain = profile->domain_name;
4129 		}
4130 
4131 		select_from_profile(profile, user, domain, concat, exclude_contact, match_user_agent, &mystream, SWITCH_FALSE);
4132 		sofia_glue_release_profile(profile);
4133 
4134 	} else if (!zstr(domain)) {
4135 		sofia_profile_t *profiles[1024] = {0};
4136 		uint8_t i = 0, j;
4137 		switch_mutex_lock(mod_sofia_globals.hash_mutex);
4138 		if (mod_sofia_globals.profile_hash) {
4139 			switch_hash_index_t *hi;
4140 			const void *var;
4141 			void *val;
4142 
4143 			for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
4144 				switch_core_hash_this(hi, &var, NULL, &val);
4145 				if ((profile = (sofia_profile_t *) val) && !strcmp((char *)var, profile->name)) {
4146 					sofia_glue_profile_rdlock(profile);
4147 					profiles[i++] = profile;
4148 					profile = NULL;
4149 				}
4150 			}
4151 		}
4152 		switch_mutex_unlock(mod_sofia_globals.hash_mutex);
4153 		if (i) {
4154 			for (j = 0; j < i; j++) {
4155 				select_from_profile(profiles[j], user, domain, concat, exclude_contact, match_user_agent, &mystream, SWITCH_TRUE);
4156 				sofia_glue_release_profile(profiles[j]);
4157 			}
4158 		}
4159 	}
4160 
4161 	reply = (char *) mystream.data;
4162 
4163 	if (zstr(reply)) {
4164 		reply = "error/user_not_registered";
4165 	} else if (end_of(reply) == ',') {
4166 		end_of(reply) = '\0';
4167 	}
4168 
4169 	stream->write_function(stream, "%s", reply);
4170 	reply = NULL;
4171 
4172 	switch_safe_free(mystream.data);
4173 
4174 	switch_safe_free(data);
4175 	switch_safe_free(dup_domain);
4176 
4177 	return SWITCH_STATUS_SUCCESS;
4178 }
4179 
4180 struct list_result {
4181 	int row_process;
4182 	int single_col;
4183 	switch_stream_handle_t *stream;
4184 
4185 };
list_result_callback(void * pArg,int argc,char ** argv,char ** columnNames)4186 static int list_result_callback(void *pArg, int argc, char **argv, char **columnNames)
4187 {
4188 	struct list_result *cbt = (struct list_result *) pArg;
4189 	int i = 0;
4190 
4191 	cbt->row_process++;
4192 
4193 	if (cbt->row_process == 1) {
4194 		for ( i = 0; i < argc; i++) {
4195 			cbt->stream->write_function(cbt->stream,"%s", columnNames[i]);
4196 			if (i < argc - 1) {
4197 				cbt->stream->write_function(cbt->stream,"|");
4198 			}
4199 		}
4200 		cbt->stream->write_function(cbt->stream,"\n");
4201 
4202 	}
4203 	for ( i = 0; i < argc; i++) {
4204 		cbt->stream->write_function(cbt->stream,"%s", zstr(argv[i]) ? "unknown" : argv[i]);
4205 		if (i < argc - 1) {
4206 			cbt->stream->write_function(cbt->stream,"|");
4207 		}
4208 	}
4209 	if (!cbt->single_col)
4210 		cbt->stream->write_function(cbt->stream,"\n");
4211 	return 0;
4212 }
4213 
4214 
get_presence_data(sofia_profile_t * profile,const char * user,const char * domain,const char * search,switch_stream_handle_t * stream)4215 static void get_presence_data(sofia_profile_t *profile, const char *user, const char *domain, const char *search, switch_stream_handle_t *stream)
4216 {
4217 	struct list_result cb;
4218 	char *sql;
4219 	char *select;
4220 
4221 	cb.row_process = 1;
4222 	cb.single_col = 1;
4223 	cb.stream = stream;
4224 
4225 	if (!strcasecmp(search, "status")) {
4226 		select = switch_mprintf(" p.status ");
4227 	} else if (!strcasecmp(search, "rpid")) {
4228 		select = switch_mprintf(" p.rpid ");
4229 	} else if (!strcasecmp(search, "user_agent")) {
4230 		select = switch_mprintf(" r.user_agent ");
4231 	}  else {
4232 		cb.row_process = 0;
4233 		cb.single_col = 0;
4234 		select = switch_mprintf(" p.status, p.rpid, r.user_agent,  r.network_ip, r.network_port ");
4235 	}
4236 
4237 	sql = switch_mprintf(" select %q from sip_registrations as r left join sip_presence as p "
4238 		" on p.sip_host = r.sip_host and p.profile_name = r.profile_name and p.hostname = r.orig_hostname "
4239 		" and p.sip_user = r.sip_user "
4240 		" where r.sip_realm = '%q' and r.sip_user = '%q' and r.profile_name = '%q' ", select, domain, user, profile->name);
4241 
4242 	switch_assert(sql);
4243 	sofia_glue_execute_sql_callback(profile, profile->dbh_mutex, sql, list_result_callback, &cb);
4244 	switch_safe_free(sql);
4245 	switch_safe_free(select);
4246 }
4247 
4248 /* [list|status|rpid|user_agent] [profile/]<user>@domain */
SWITCH_STANDARD_API(sofia_presence_data_function)4249 SWITCH_STANDARD_API(sofia_presence_data_function)
4250 {
4251 	char *argv[6] = { 0 };
4252 	int argc;
4253 	char *data;
4254 	char *user = NULL;
4255 	char *domain = NULL, *dup_domain = NULL;
4256 	char *concat = NULL;
4257 	char *search = NULL;
4258 	char *profile_name = NULL;
4259 	char *p;
4260 	sofia_profile_t *profile = NULL;
4261 
4262 	if (!cmd) {
4263 		stream->write_function(stream, "%s", "");
4264 		return SWITCH_STATUS_SUCCESS;
4265 	}
4266 
4267 	data = strdup(cmd);
4268 	switch_assert(data);
4269 
4270 
4271 	argc = switch_separate_string(data, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
4272 	if (argc < 2) {
4273 		stream->write_function(stream, "%s", "");
4274 		return SWITCH_STATUS_SUCCESS;
4275 	}
4276 	search = argv[0];
4277 
4278 	if ((p = strchr(argv[1], '/'))) {
4279 		profile_name = argv[1];
4280 		*p++ = '\0';
4281 		user = p;
4282 	} else {
4283 		user = argv[1];
4284 	}
4285 
4286 	if ((domain = strchr(user, '@'))) {
4287 		*domain++ = '\0';
4288 		if ((concat = strchr(domain, '/'))) {
4289 			*concat++ = '\0';
4290 		}
4291 	} else {
4292 		if (user && (concat = strchr(user, '/'))) {
4293 			*concat++ = '\0';
4294 		}
4295 	}
4296 
4297 	if (zstr(domain)) {
4298 		dup_domain = switch_core_get_domain(SWITCH_TRUE);
4299 		domain = dup_domain;
4300 	}
4301 
4302 	if (!user) goto end;
4303 
4304 	if (zstr(profile_name) || strcmp(profile_name, "*") || zstr(domain)) {
4305 		if (!zstr(profile_name)) {
4306 			profile = sofia_glue_find_profile(profile_name);
4307 		}
4308 
4309 		if (!profile && !zstr(domain)) {
4310 			profile = sofia_glue_find_profile(domain);
4311 		}
4312 	}
4313 
4314 	if (profile) {
4315 		if (zstr(domain)) {
4316 			domain = profile->name;
4317 		}
4318 
4319 		if (!zstr(profile->domain_name) && !zstr(profile_name) && !strcmp(profile_name, profile->name)) {
4320 			domain = profile->domain_name;
4321 		}
4322 
4323 		get_presence_data(profile, user, domain, search, stream);
4324 		sofia_glue_release_profile(profile);
4325 
4326 	} else if (!zstr(domain)) {
4327 		switch_mutex_lock(mod_sofia_globals.hash_mutex);
4328 		if (mod_sofia_globals.profile_hash) {
4329 			switch_hash_index_t *hi;
4330 			const void *var;
4331 			void *val;
4332 
4333 			for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
4334 				switch_core_hash_this(hi, &var, NULL, &val);
4335 				if ((profile = (sofia_profile_t *) val) && !strcmp((char *)var, profile->name)) {
4336 					get_presence_data(profile, user, domain, search, stream);
4337 					profile = NULL;
4338 				}
4339 			}
4340 		}
4341 		switch_mutex_unlock(mod_sofia_globals.hash_mutex);
4342 	}
4343 
4344 	if (!strcasecmp(search, "list"))
4345 		stream->write_function(stream, "+OK\n");
4346 
4347  end:
4348 	switch_safe_free(data);
4349 	switch_safe_free(dup_domain);
4350 
4351 	return SWITCH_STATUS_SUCCESS;
4352 }
4353 
4354 /* <gateway_name> [ivar|ovar|var] <name> */
SWITCH_STANDARD_API(sofia_gateway_data_function)4355 SWITCH_STANDARD_API(sofia_gateway_data_function)
4356 {
4357 	char *argv[4];
4358 	char *mydata;
4359 	int argc;
4360 	sofia_gateway_t *gateway;
4361 	char *gwname, *param, *varname;
4362 	const char *val = NULL;
4363 
4364 	if (zstr(cmd)) {
4365 		stream->write_function(stream, "-ERR Parameter missing\n");
4366 		return SWITCH_STATUS_SUCCESS;
4367 	}
4368 	if (!(mydata = strdup(cmd))) {
4369 		return SWITCH_STATUS_FALSE;
4370 	}
4371 
4372 	if (!(argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
4373 		goto end;
4374 	}
4375 
4376 	gwname = argv[0];
4377 	param = argv[1];
4378 	varname = argv[2];
4379 
4380 	if (zstr(gwname) || zstr(param) || zstr(varname)) {
4381 		goto end;
4382 	}
4383 
4384 	if (!(gateway = sofia_reg_find_gateway(gwname))) {
4385 		goto end;
4386 	}
4387 
4388 	if (!strcasecmp(param, "ivar") && gateway->ib_vars && (val = switch_event_get_header(gateway->ib_vars, varname))) {
4389 		stream->write_function(stream, "%s", val);
4390 	} else if (!strcasecmp(param, "ovar") && gateway->ob_vars && (val = switch_event_get_header(gateway->ob_vars, varname))) {
4391 		stream->write_function(stream, "%s", val);
4392 	} else if (!strcasecmp(param, "var")) {
4393 		if (gateway->ib_vars && (val = switch_event_get_header(gateway->ib_vars, varname))) {
4394 			stream->write_function(stream, "%s", val);
4395 		} else if (gateway->ob_vars && (val = switch_event_get_header(gateway->ob_vars, varname))) {
4396 			stream->write_function(stream, "%s", val);
4397 		}
4398 	}
4399 
4400 	sofia_reg_release_gateway(gateway);
4401 
4402   end:
4403 	switch_safe_free(mydata);
4404 	return SWITCH_STATUS_SUCCESS;
4405 }
4406 
SWITCH_STANDARD_API(sofia_function)4407 SWITCH_STANDARD_API(sofia_function)
4408 {
4409 	char *argv[1024] = { 0 };
4410 	int argc = 0;
4411 	char *mycmd = NULL;
4412 	switch_status_t status = SWITCH_STATUS_SUCCESS;
4413 	sofia_command_t func = NULL;
4414 	int lead = 1;
4415 	static const char usage_string[] = "USAGE:\n"
4416 		"--------------------------------------------------------------------------------\n"
4417 		"sofia global siptrace <on|off>\n"
4418 		"sofia        capture  <on|off>\n"
4419 		"             watchdog <on|off>\n\n"
4420 		"sofia profile <name> [start | stop | restart | rescan] [wait]\n"
4421 		"                     flush_inbound_reg [<call_id> | <[user]@domain>] [reboot]\n"
4422 		"                     check_sync [<call_id> | <[user]@domain>]\n"
4423 		"                     [register | unregister] [<gateway name> | all]\n"
4424 		"                     killgw <gateway name>\n"
4425 		"                     [stun-auto-disable | stun-enabled] [true | false]]\n"
4426 		"                     siptrace <on|off>\n"
4427 		"                     capture  <on|off>\n"
4428 		"                     watchdog <on|off>\n\n"
4429 		"sofia <status|xmlstatus> profile <name> [reg [<contact str>]] | [pres <pres str>] | [user <user@domain>]\n"
4430 		"sofia <status|xmlstatus> gateway <name>\n\n"
4431 		"sofia loglevel <all|default|tport|iptsec|nea|nta|nth_client|nth_server|nua|soa|sresolv|stun> [0-9]\n"
4432 		"sofia tracelevel <console|alert|crit|err|warning|notice|info|debug>\n\n"
4433 		"sofia help\n"
4434 		"--------------------------------------------------------------------------------\n";
4435 
4436 	if (zstr(cmd)) {
4437 		stream->write_function(stream, "%s", usage_string);
4438 		goto done;
4439 	}
4440 
4441 	if (!(mycmd = strdup(cmd))) {
4442 		status = SWITCH_STATUS_MEMERR;
4443 		goto done;
4444 	}
4445 
4446 	if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
4447 		stream->write_function(stream, "%s", usage_string);
4448 		goto done;
4449 	}
4450 
4451 	if (!strcasecmp(argv[0], "profile")) {
4452 		func = cmd_profile;
4453 	} else if (!strcasecmp(argv[0], "status")) {
4454 		func = cmd_status;
4455 	} else if (!strcasecmp(argv[0], "xmlstatus")) {
4456 		func = cmd_xml_status;
4457 	} else if (!strcasecmp(argv[0], "jsonstatus")) {
4458 		func = cmd_json_status;
4459 	} else if (!strcasecmp(argv[0], "tracelevel")) {
4460 		if (argv[1]) {
4461 			mod_sofia_globals.tracelevel = switch_log_str2level(argv[1]);
4462 		}
4463 		stream->write_function(stream, "+OK tracelevel is %s", switch_log_level2str(mod_sofia_globals.tracelevel));
4464 		goto done;
4465 	} else if (!strcasecmp(argv[0], "loglevel")) {
4466 		if (argc > 2 && argv[2] && switch_is_number(argv[2])) {
4467 			int level = atoi(argv[2]);
4468 			if (sofia_set_loglevel(argv[1], level) == SWITCH_STATUS_SUCCESS) {
4469 				stream->write_function(stream, "Sofia log level for component [%s] has been set to [%d]", argv[1], level);
4470 			} else {
4471 				stream->write_function(stream, "%s", usage_string);
4472 			}
4473 		} else if (argc > 1 && argv[1]) {
4474 			int level = sofia_get_loglevel(argv[1]);
4475 			if (level >= 0) {
4476 				stream->write_function(stream, "Sofia-sip loglevel for [%s] is [%d]", argv[1], level);
4477 			} else {
4478 				stream->write_function(stream, "%s", usage_string);
4479 			}
4480 		} else {
4481 			stream->write_function(stream, "%s", usage_string);
4482 		}
4483 		goto done;
4484 	} else if (!strcasecmp(argv[0], "help")) {
4485 		stream->write_function(stream, "%s", usage_string);
4486 		goto done;
4487 	} else if (!strcasecmp(argv[0], "global")) {
4488 		int ston = -1;
4489 		int cton = -1;
4490 		int wdon = -1;
4491 		int stbyon = -1;
4492 
4493 		if (argc > 1) {
4494 			if (!strcasecmp(argv[1], "debug")) {
4495 
4496 				if (argc > 2) {
4497 					if (strstr(argv[2], "presence")) {
4498 						mod_sofia_globals.debug_presence = 10;
4499 						stream->write_function(stream, "+OK Debugging presence\n");
4500 					}
4501 
4502 					if (strstr(argv[2], "sla")) {
4503 						mod_sofia_globals.debug_sla = 10;
4504 						stream->write_function(stream, "+OK Debugging sla\n");
4505 					}
4506 
4507 					if (strstr(argv[2], "none")) {
4508 						stream->write_function(stream, "+OK Debugging nothing\n");
4509 						mod_sofia_globals.debug_presence = 0;
4510 						mod_sofia_globals.debug_sla = 0;
4511 					}
4512 				}
4513 
4514 				stream->write_function(stream, "+OK Debugging summary: presence: %s sla: %s\n",
4515 									   mod_sofia_globals.debug_presence ? "on" : "off",
4516 									   mod_sofia_globals.debug_sla ? "on" : "off");
4517 
4518 				goto done;
4519 			}
4520 
4521 			if (!strcasecmp(argv[1], "siptrace")) {
4522 				if (argc > 2) {
4523 					ston = switch_true(argv[2]);
4524 				}
4525 			}
4526 
4527 			if (!strcasecmp(argv[1], "standby")) {
4528 				if (argc > 2) {
4529 					stbyon = switch_true(argv[2]);
4530 				}
4531 			}
4532 
4533 			if (!strcasecmp(argv[1], "capture")) {
4534 							if (argc > 2) {
4535 										cton = switch_true(argv[2]);
4536 								}
4537 						}
4538 
4539 			if (!strcasecmp(argv[1], "watchdog")) {
4540 				if (argc > 2) {
4541 					wdon = switch_true(argv[2]);
4542 				}
4543 			}
4544 		}
4545 
4546 		if (ston != -1) {
4547 			sofia_glue_global_siptrace(ston);
4548 			stream->write_function(stream, "+OK Global siptrace %s", ston ? "on" : "off");
4549 		} else if (cton != -1) {
4550 			sofia_glue_global_capture(cton);
4551 			stream->write_function(stream, "+OK Global capture %s", cton ? "on" : "off");
4552 		} else if (wdon != -1) {
4553 			sofia_glue_global_watchdog(wdon);
4554 			stream->write_function(stream, "+OK Global watchdog %s", wdon ? "on" : "off");
4555 		} else if (stbyon != -1) {
4556 			sofia_glue_global_standby(stbyon);
4557 			stream->write_function(stream, "+OK Global standby %s", stbyon ? "on" : "off");
4558 		} else {
4559 			stream->write_function(stream, "-ERR Usage: siptrace <on|off>|capture <on|off>|watchdog <on|off>|debug <sla|presence|none");
4560 		}
4561 
4562 		goto done;
4563 
4564 	} else if (!strcasecmp(argv[0], "recover")) {
4565 		if (argv[1] && !strcasecmp(argv[1], "flush")) {
4566 			sofia_glue_recover(SWITCH_TRUE);
4567 			stream->write_function(stream, "Flushing recovery database.\n");
4568 		} else {
4569 			int x = sofia_glue_recover(SWITCH_FALSE);
4570 			switch_event_t *event = NULL;
4571 
4572 			if (x) {
4573 				if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM,
4574 					MY_EVENT_RECOVERY_RECOVERED) == SWITCH_STATUS_SUCCESS) {
4575 					switch_event_add_header(event, SWITCH_STACK_BOTTOM, "recovered_calls", "%d", x);
4576 					switch_event_fire(&event);
4577 				}
4578 
4579 				stream->write_function(stream, "Recovered %d call(s)\n", x);
4580 			} else {
4581 				if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM,
4582 					MY_EVENT_RECOVERY_RECOVERED) == SWITCH_STATUS_SUCCESS) {
4583 					switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "recovered_calls", "0");
4584 					switch_event_fire(&event);
4585 				}
4586 
4587 				stream->write_function(stream, "No calls to recover.\n");
4588 			}
4589 		}
4590 
4591 		goto done;
4592 	}
4593 
4594 	if (func) {
4595 		status = func(&argv[lead], argc - lead, stream);
4596 	} else {
4597 		stream->write_function(stream, "Unknown Command [%s]\n", argv[0]);
4598 	}
4599 
4600   done:
4601 	switch_safe_free(mycmd);
4602 	return status;
4603 }
4604 
4605 switch_io_routines_t sofia_io_routines = {
4606 	/*.outgoing_channel */ sofia_outgoing_channel,
4607 	/*.read_frame */ sofia_read_frame,
4608 	/*.write_frame */ sofia_write_frame,
4609 	/*.kill_channel */ sofia_kill_channel,
4610 	/*.send_dtmf */ sofia_send_dtmf,
4611 	/*.receive_message */ sofia_receive_message,
4612 	/*.receive_event */ sofia_receive_event,
4613 	/*.state_change */ NULL,
4614 	/*.read_video_frame */ sofia_read_video_frame,
4615 	/*.write_video_frame */ sofia_write_video_frame,
4616 	/*.read_text_frame */ sofia_read_text_frame,
4617 	/*.write_text_frame */ sofia_write_text_frame,
4618 	/*.state_run*/ NULL,
4619 	/*.get_jb*/ sofia_get_jb
4620 };
4621 
4622 switch_state_handler_table_t sofia_event_handlers = {
4623 	/*.on_init */ sofia_on_init,
4624 	/*.on_routing */ sofia_on_routing,
4625 	/*.on_execute */ sofia_on_execute,
4626 	/*.on_hangup */ sofia_on_hangup,
4627 	/*.on_exchange_media */ sofia_on_exchange_media,
4628 	/*.on_soft_execute */ sofia_on_soft_execute,
4629 	/*.on_consume_media */ NULL,
4630 	/*.on_hibernate */ sofia_on_hibernate,
4631 	/*.on_reset */ sofia_on_reset,
4632 	/*.on_park */ NULL,
4633 	/*.on_reporting */ NULL,
4634 	/*.on_destroy */ sofia_on_destroy
4635 };
4636 
sofia_manage(char * relative_oid,switch_management_action_t action,char * data,switch_size_t datalen)4637 static switch_status_t sofia_manage(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen)
4638 {
4639 	return SWITCH_STATUS_SUCCESS;
4640 }
4641 
protect_dest_uri(switch_caller_profile_t * cp)4642 static int protect_dest_uri(switch_caller_profile_t *cp)
4643 {
4644 	char *p = cp->destination_number, *o = p;
4645 	char *q = NULL, *e = NULL, *qenc = NULL;
4646 	switch_size_t enclen = 0;
4647 	int mod = 0;
4648 
4649 	if (!(e = strchr(p, '@'))) {
4650 		return 0;
4651 	}
4652 
4653 	while((p = strchr(p, '/'))) {
4654 		q = p++;
4655 	}
4656 
4657 	if (q) {
4658 		const char *i;
4659 		int go = 0;
4660 
4661 		for (i = q+1; i && *i && *i != '@'; i++) {
4662 			if (strchr(SWITCH_URL_UNSAFE, *i)) {
4663 				go = 1;
4664 			}
4665 		}
4666 
4667 		if (!go) return 0;
4668 
4669 		*q++ = '\0';
4670 	} else {
4671 		return 0;
4672 	}
4673 
4674 	if (!strncasecmp(q, "sips:", 5)) {
4675 		q += 5;
4676 	} else if (!strncasecmp(q, "sip:", 4)) {
4677 		q += 4;
4678 	}
4679 
4680 	if (!(e = strchr(q, '@'))) {
4681 		return 0;
4682 	}
4683 
4684 	*e++ = '\0';
4685 
4686 	if (switch_needs_url_encode(q)) {
4687 		enclen = (strlen(q) * 3)  + 2;
4688 		qenc = switch_core_alloc(cp->pool, enclen);
4689 		switch_url_encode(q, qenc, enclen);
4690 		mod = 1;
4691 	}
4692 
4693 	cp->destination_number = switch_core_sprintf(cp->pool, "%s/%s@%s", o, qenc ? qenc : q, e);
4694 
4695 	return mod;
4696 }
4697 
sofia_outgoing_channel(switch_core_session_t * session,switch_event_t * var_event,switch_caller_profile_t * outbound_profile,switch_core_session_t ** new_session,switch_memory_pool_t ** pool,switch_originate_flag_t flags,switch_call_cause_t * cancel_cause)4698 static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
4699 												  switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
4700 												  switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause)
4701 {
4702 	switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
4703 	switch_core_session_t *nsession = NULL;
4704 	char *data, *profile_name, *dest;	//, *dest_num = NULL;
4705 	sofia_profile_t *profile = NULL;
4706 	switch_caller_profile_t *caller_profile = NULL;
4707 	private_object_t *tech_pvt = NULL;
4708 	switch_channel_t *nchannel;
4709 	char *host = NULL, *dest_to = NULL;
4710 	const char *hval = NULL;
4711 	char *not_const = NULL;
4712 	int cid_locked = 0;
4713 	switch_channel_t *o_channel = NULL;
4714 	sofia_gateway_t *gateway_ptr = NULL;
4715 	int mod = 0;
4716 
4717 	*new_session = NULL;
4718 
4719 	if (!outbound_profile || zstr(outbound_profile->destination_number)) {
4720 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Invalid Empty Destination\n");
4721 		goto error;
4722 	}
4723 
4724 	if (!switch_true(switch_event_get_header(var_event, "sofia_suppress_url_encoding"))) {
4725 		mod = protect_dest_uri(outbound_profile);
4726 	}
4727 
4728 	if (!(nsession = switch_core_session_request_uuid(sofia_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND,
4729 													  flags, pool, switch_event_get_header(var_event, "origination_uuid")))) {
4730 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
4731 		goto error;
4732 	}
4733 
4734 	tech_pvt = sofia_glue_new_pvt(nsession);
4735 
4736 	data = switch_core_session_strdup(nsession, outbound_profile->destination_number);
4737 	if ((dest_to = strchr(data, '^'))) {
4738 		*dest_to++ = '\0';
4739 	}
4740 	profile_name = data;
4741 
4742 	nchannel = switch_core_session_get_channel(nsession);
4743 
4744 	if (session) {
4745 		o_channel = switch_core_session_get_channel(session);
4746 	}
4747 
4748 
4749 	if ((hval = switch_event_get_header(var_event, "sip_invite_to_uri"))) {
4750 		dest_to = switch_core_session_strdup(nsession, hval);
4751 	}
4752 
4753 	if (!strncasecmp(profile_name, "gateway/", 8)) {
4754 		char *gw, *params;
4755 
4756 		if (!(gw = strchr(profile_name, '/'))) {
4757 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid URL \'%s\'\n", profile_name);
4758 			cause = SWITCH_CAUSE_INVALID_URL;
4759 			goto error;
4760 		}
4761 
4762 		*gw++ = '\0';
4763 
4764 		if (!(dest = strchr(gw, '/'))) {
4765 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid URL \'%s\'\n", gw);
4766 			cause = SWITCH_CAUSE_INVALID_URL;
4767 			goto error;
4768 		}
4769 
4770 		*dest++ = '\0';
4771 
4772 		if (!(gateway_ptr = sofia_reg_find_gateway(gw))) {
4773 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Gateway \'%s\'\n", gw);
4774 			cause = SWITCH_CAUSE_INVALID_GATEWAY;
4775 			goto error;
4776 		}
4777 
4778 		profile = gateway_ptr->profile;
4779 
4780 		if (gateway_ptr->status != SOFIA_GATEWAY_UP) {
4781 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Gateway \'%s\' is down!\n", gw);
4782 			cause = SWITCH_CAUSE_GATEWAY_DOWN;
4783 			gateway_ptr->ob_failed_calls++;
4784 			goto error;
4785 		}
4786 
4787 		tech_pvt->transport = gateway_ptr->register_transport;
4788 		tech_pvt->cid_type = gateway_ptr->cid_type;
4789 		cid_locked = 1;
4790 
4791 		/*
4792 		 * Handle params, strip them off the destination and add them to the
4793 		 * invite contact.
4794 		 *
4795 		 */
4796 
4797 		if ((params = strchr(dest, ';'))) {
4798 			char *tp_param;
4799 
4800 			*params++ = '\0';
4801 
4802 			if ((tp_param = (char *) switch_stristr("port=", params))) {
4803 				tp_param += 5;
4804 				tech_pvt->transport = sofia_glue_str2transport(tp_param);
4805 				if (tech_pvt->transport == SOFIA_TRANSPORT_UNKNOWN) {
4806 					cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
4807 					gateway_ptr->ob_failed_calls++;
4808 					goto error;
4809 				}
4810 			}
4811 		}
4812 
4813 		if (tech_pvt->transport != gateway_ptr->register_transport) {
4814 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR,
4815 							  "You are trying to use a different transport type for this gateway (overriding the register-transport), this is unsupported!\n");
4816 			cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
4817 			goto error;
4818 		}
4819 
4820 		if (profile && sofia_test_pflag(profile, PFLAG_STANDBY)) {
4821 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "System Paused\n");
4822 			cause = SWITCH_CAUSE_SYSTEM_SHUTDOWN;
4823 			goto error;
4824 		}
4825 
4826 		tech_pvt->gateway_name = switch_core_session_strdup(nsession, gateway_ptr->name);
4827 		switch_channel_set_variable(nchannel, "sip_gateway_name", gateway_ptr->name);
4828 
4829 		if (!sofia_test_flag(gateway_ptr, REG_FLAG_CALLERID)) {
4830 			tech_pvt->gateway_from_str = switch_core_session_strdup(nsession, gateway_ptr->register_from);
4831 		}
4832 
4833 		if (!strchr(dest, '@')) {
4834 			tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s%s@%s", gateway_ptr->destination_prefix, dest, sofia_glue_strip_proto(gateway_ptr->register_proxy));
4835 		} else {
4836 			tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s%s", gateway_ptr->destination_prefix, dest);
4837 		}
4838 
4839 		if ((host = switch_core_session_strdup(nsession, tech_pvt->dest))) {
4840 			char *pp = strchr(host, '@');
4841 			if (pp) {
4842 				host = pp + 1;
4843 			} else {
4844 				host = NULL;
4845 				dest_to = NULL;
4846 			}
4847 		}
4848 
4849 		if (params) {
4850 			tech_pvt->invite_contact = switch_core_session_sprintf(nsession, "%s;%s", gateway_ptr->register_contact, params);
4851 			tech_pvt->dest = switch_core_session_sprintf(nsession, "%s;%s", tech_pvt->dest, params);
4852 		} else {
4853 			tech_pvt->invite_contact = switch_core_session_strdup(nsession, gateway_ptr->register_contact);
4854 		}
4855 
4856 		gateway_ptr->ob_calls++;
4857 
4858 		if (!zstr(gateway_ptr->from_domain) && !switch_channel_get_variable(nchannel, "sip_invite_domain")) {
4859 
4860 			if (!strcasecmp(gateway_ptr->from_domain, "auto-aleg-full")) {
4861 				const char *sip_full_from = switch_channel_get_variable(o_channel, "sip_full_from");
4862 
4863 				if (!zstr(sip_full_from)) {
4864 					switch_channel_set_variable(nchannel, "sip_force_full_from", sip_full_from);
4865 				}
4866 
4867 			} else if (!strcasecmp(gateway_ptr->from_domain, "auto-aleg-domain")) {
4868 				const char *sip_from_host = switch_channel_get_variable(o_channel, "sip_from_host");
4869 
4870 				if (!zstr(sip_from_host)) {
4871 					switch_channel_set_variable(nchannel, "sip_invite_domain", sip_from_host);
4872 				}
4873 			} else {
4874 				switch_channel_set_variable(nchannel, "sip_invite_domain", gateway_ptr->from_domain);
4875 			}
4876 		}
4877 
4878 		if (!zstr(gateway_ptr->outbound_sticky_proxy) && !switch_channel_get_variable(nchannel, "sip_route_uri")) {
4879 			switch_channel_set_variable(nchannel, "sip_route_uri", gateway_ptr->outbound_sticky_proxy);
4880 		}
4881 
4882 	} else {
4883 		if (!(dest = strchr(profile_name, '/'))) {
4884 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid URL\n");
4885 			cause = SWITCH_CAUSE_INVALID_URL;
4886 			goto error;
4887 		}
4888 		*dest++ = '\0';
4889 
4890 		if (!(profile = sofia_glue_find_profile(profile_name))) {
4891 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid Profile\n");
4892 			cause = SWITCH_CAUSE_INVALID_PROFILE;
4893 			goto error;
4894 		}
4895 
4896 		if (sofia_test_pflag(profile, PFLAG_STANDBY)) {
4897 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "System Paused\n");
4898 			cause = SWITCH_CAUSE_SYSTEM_SHUTDOWN;
4899 			goto error;
4900 		}
4901 
4902 		if (profile->domain_name && strcmp(profile->domain_name, profile->name)) {
4903 			profile_name = profile->domain_name;
4904 		}
4905 
4906 		if (!strncasecmp(dest, "sip:", 4) || !strncasecmp(dest, "sips:", 5)) {
4907 			char *c;
4908 			tech_pvt->dest = switch_core_session_strdup(nsession, dest);
4909 			if ((c = strchr(tech_pvt->dest, ':'))) {
4910 				c++;
4911 				tech_pvt->e_dest = switch_core_session_strdup(nsession, c);
4912 			}
4913 		} else if (!mod && !strchr(dest, '@') && (host = strchr(dest, '%'))) {
4914 			char buf[1024];
4915 			*host = '@';
4916 			tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
4917 			*host++ = '\0';
4918 			if (sofia_reg_find_reg_url(profile, dest, host, buf, sizeof(buf))) {
4919 				tech_pvt->dest = switch_core_session_strdup(nsession, buf);
4920 				tech_pvt->local_url = switch_core_session_sprintf(nsession, "%s@%s", dest, host);
4921 			} else {
4922 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, host);
4923 				cause = SWITCH_CAUSE_USER_NOT_REGISTERED;
4924 				goto error;
4925 			}
4926 		} else if (!(host = strchr(dest, '@'))) {
4927 			char buf[1024];
4928 			tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
4929 			if (sofia_reg_find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) {
4930 				tech_pvt->dest = switch_core_session_strdup(nsession, buf);
4931 				tech_pvt->local_url = switch_core_session_sprintf(nsession, "%s@%s", dest, profile_name);
4932 				host = profile_name;
4933 			} else {
4934 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, profile_name);
4935 				cause = SWITCH_CAUSE_USER_NOT_REGISTERED;
4936 				goto error;
4937 			}
4938 		} else {
4939 			host++;
4940 
4941 			if (!strchr(host, '.') || switch_true(switch_event_get_header(var_event, "sip_gethostbyname"))) {
4942 				struct sockaddr_in sa;
4943 				struct hostent *he = gethostbyname(host);
4944 				char buf[50] = "", *tmp;
4945 				const char *ip;
4946 
4947 				if (he) {
4948 					memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
4949 					ip = switch_inet_ntop(AF_INET, &sa.sin_addr, buf, sizeof(buf));
4950 					tmp = switch_string_replace(dest, host, ip);
4951 					//host = switch_core_session_strdup(nsession, ip);
4952 					//dest = switch_core_session_strdup(nsession, tmp);
4953 					switch_channel_set_variable_printf(nchannel, "sip_route_uri", "sip:%s", tmp);
4954 					free(tmp);
4955 				}
4956 			}
4957 
4958 			tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5);
4959 			tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
4960 			switch_snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest);
4961 		}
4962 	}
4963 
4964 	switch_channel_set_variable_printf(nchannel, "sip_local_network_addr", "%s", profile->extsipip ? profile->extsipip : profile->sipip);
4965 	switch_channel_set_variable(nchannel, "sip_profile_name", profile_name);
4966 
4967 	if (switch_stristr("fs_path", tech_pvt->dest)) {
4968 		char *remote_host = NULL;
4969 		const char *s;
4970 
4971 		if ((s = switch_stristr("fs_path=", tech_pvt->dest))) {
4972 			s += 8;
4973 		}
4974 
4975 		if (s) {
4976 			remote_host = switch_core_session_strdup(nsession, s);
4977 			switch_url_decode(remote_host);
4978 		}
4979 		if (!zstr(remote_host)) {
4980 			switch_split_user_domain(remote_host, NULL, &tech_pvt->mparams.remote_ip);
4981 		}
4982 	}
4983 
4984 	if (zstr(tech_pvt->mparams.remote_ip)) {
4985 		switch_split_user_domain(switch_core_session_strdup(nsession, tech_pvt->dest), NULL, &tech_pvt->mparams.remote_ip);
4986 	}
4987 
4988 	if (dest_to) {
4989 		if (strchr(dest_to, '@')) {
4990 			tech_pvt->dest_to = switch_core_session_sprintf(nsession, "sip:%s", dest_to);
4991 		} else {
4992 			tech_pvt->dest_to = switch_core_session_sprintf(nsession, "sip:%s@%s", dest_to, host ? host : profile->sipip);
4993 		}
4994 	}
4995 
4996 	if (!tech_pvt->dest_to) {
4997 		tech_pvt->dest_to = tech_pvt->dest;
4998 	}
4999 
5000 	if (!zstr(tech_pvt->dest) && switch_stristr("transport=ws", tech_pvt->dest)) {
5001 		switch_channel_set_variable(nchannel, "media_webrtc", "true");
5002 		switch_core_session_set_ice(nsession);
5003 	}
5004 
5005 
5006 	sofia_glue_attach_private(nsession, profile, tech_pvt, dest);
5007 
5008 	if (tech_pvt->local_url) {
5009 		switch_channel_set_variable(nchannel, "sip_local_url", tech_pvt->local_url);
5010 		if (profile->pres_type) {
5011 			const char *presence_id = switch_channel_get_variable(nchannel, "presence_id");
5012 			if (zstr(presence_id)) {
5013 				switch_channel_set_variable(nchannel, "presence_id", tech_pvt->local_url);
5014 			}
5015 		}
5016 	}
5017 	switch_channel_set_variable(nchannel, "sip_destination_url", tech_pvt->dest);
5018 #if 0
5019 	dest_num = switch_core_session_strdup(nsession, dest);
5020 	if ((p = strchr(dest_num, '@'))) {
5021 		*p = '\0';
5022 
5023 		if ((p = strrchr(dest_num, '/'))) {
5024 			dest_num = p + 1;
5025 		} else if ((p = (char *) switch_stristr("sip:", dest_num))) {
5026 			dest_num = p + 4;
5027 		} else if ((p = (char *) switch_stristr("sips:", dest_num))) {
5028 			dest_num = p + 5;
5029 		}
5030 	}
5031 
5032 
5033 	if (profile->pres_type) {
5034 		char *sql;
5035 		time_t now;
5036 
5037 		const char *presence_id = switch_channel_get_variable(nchannel, "presence_id");
5038 		const char *presence_data = switch_channel_get_variable(nchannel, "presence_data");
5039 
5040 		if (zstr(presence_id)) {
5041 			presence_id = switch_event_get_header(var_event, "presence_id");
5042 		}
5043 
5044 		if (zstr(presence_data)) {
5045 			presence_data = switch_event_get_header(var_event, "presence_data");
5046 		}
5047 
5048 		now = switch_epoch_time_now(NULL);
5049 		sql = switch_mprintf("insert into sip_dialogs (uuid,presence_id,presence_data,profile_name,hostname,rcd,call_info_state) "
5050 							 "values ('%q', '%q', '%q', '%q', '%q', %ld, '')", switch_core_session_get_uuid(nsession),
5051 							 switch_str_nil(presence_id), switch_str_nil(presence_data), profile->name, mod_sofia_globals.hostname, (long) now);
5052 		sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
5053 	}
5054 #endif
5055 
5056 	caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
5057 
5058 
5059 	caller_profile->destination_number = switch_sanitize_number(caller_profile->destination_number);
5060 	not_const = (char *) caller_profile->caller_id_name;
5061 	caller_profile->caller_id_name = switch_sanitize_number(not_const);
5062 	not_const = (char *) caller_profile->caller_id_number;
5063 	caller_profile->caller_id_number = switch_sanitize_number(not_const);
5064 
5065 
5066 	//caller_profile->destination_number = switch_core_strdup(caller_profile->pool, dest_num);
5067 	switch_channel_set_caller_profile(nchannel, caller_profile);
5068 
5069 
5070 	if (gateway_ptr && gateway_ptr->ob_vars) {
5071 		switch_event_header_t *hp;
5072 		for (hp = gateway_ptr->ob_vars->headers; hp; hp = hp->next) {
5073 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s setting variable [%s]=[%s]\n",
5074 							  switch_channel_get_name(nchannel), hp->name, hp->value);
5075 			if (!strncmp(hp->name, "p:", 2)) {
5076 				switch_channel_set_profile_var(nchannel, hp->name + 2, hp->value);
5077 			} else {
5078 				switch_channel_set_variable(nchannel, hp->name, hp->value);
5079 			}
5080 		}
5081 	}
5082 
5083 
5084 
5085 
5086 	sofia_set_flag_locked(tech_pvt, TFLAG_OUTBOUND);
5087 	sofia_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
5088 	if (switch_channel_get_state(nchannel) == CS_NEW) {
5089 		switch_channel_set_state(nchannel, CS_INIT);
5090 	}
5091 	tech_pvt->caller_profile = caller_profile;
5092 	*new_session = nsession;
5093 	cause = SWITCH_CAUSE_SUCCESS;
5094 
5095 	if ((hval = switch_event_get_header(var_event, "sip_enable_soa"))) {
5096 		if (switch_true(hval)) {
5097 			sofia_set_flag(tech_pvt, TFLAG_ENABLE_SOA);
5098 		} else {
5099 			sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
5100 		}
5101 	}
5102 
5103 	if ((hval = switch_event_get_header(var_event, "sip_auto_answer")) && switch_true(hval)) {
5104 		switch_channel_set_variable_printf(nchannel, "sip_h_Call-Info", "<sip:%s>;answer-after=0", profile->sipip);
5105 		switch_channel_set_variable(nchannel, "sip_invite_params", "intercom=true");
5106 	}
5107 
5108 	if (((hval = switch_event_get_header(var_event, "effective_callee_id_name")) ||
5109 		 (hval = switch_event_get_header(var_event, "sip_callee_id_name"))) && !zstr(hval)) {
5110 		caller_profile->callee_id_name = switch_core_strdup(caller_profile->pool, hval);
5111 	}
5112 
5113 	if (((hval = switch_event_get_header(var_event, "effective_callee_id_number")) ||
5114 		 (hval = switch_event_get_header(var_event, "sip_callee_id_number"))) && !zstr(hval)) {
5115 		caller_profile->callee_id_number = switch_core_strdup(caller_profile->pool, hval);
5116 	}
5117 
5118 	if (session) {
5119 		const char *vval = NULL;
5120 
5121 		switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
5122 
5123 		if (!(vval = switch_channel_get_variable(o_channel, "sip_copy_custom_headers")) || switch_true(vval)) {
5124 			switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_HEADER_PREFIX_T);
5125 		}
5126 
5127 		if (!(vval = switch_channel_get_variable(o_channel, "sip_copy_multipart")) || switch_true(vval)) {
5128 			switch_ivr_transfer_variable(session, nsession, "sip_multipart");
5129 		}
5130 		switch_ivr_transfer_variable(session, nsession, "rtp_video_fmtp");
5131 		switch_ivr_transfer_variable(session, nsession, "sip-force-contact");
5132 		switch_ivr_transfer_variable(session, nsession, "sip_sticky_contact");
5133 		if (!cid_locked) {
5134 			switch_ivr_transfer_variable(session, nsession, "sip_cid_type");
5135 		}
5136 
5137 		if (switch_core_session_compare(session, nsession)) {
5138 			/* It's another sofia channel! so lets cache what they use as a pt for telephone event so
5139 			   we can keep it the same
5140 			 */
5141 			private_object_t *ctech_pvt;
5142 			ctech_pvt = switch_core_session_get_private(session);
5143 			switch_assert(ctech_pvt != NULL);
5144 			tech_pvt->bte = ctech_pvt->te;
5145 			tech_pvt->bcng_pt = ctech_pvt->cng_pt;
5146 			if (!cid_locked) {
5147 				tech_pvt->cid_type = ctech_pvt->cid_type;
5148 			}
5149 
5150 			if (sofia_test_flag(tech_pvt, TFLAG_ENABLE_SOA)) {
5151 				sofia_set_flag(ctech_pvt, TFLAG_ENABLE_SOA);
5152 			} else {
5153 				sofia_clear_flag(ctech_pvt, TFLAG_ENABLE_SOA);
5154 			}
5155 
5156 			if (switch_channel_test_flag(o_channel, CF_ZRTP_PASSTHRU_REQ) && switch_channel_test_flag(o_channel, CF_ZRTP_HASH)) {
5157 				const char *x = NULL;
5158 				switch_core_media_pass_zrtp_hash2(session, nsession);
5159 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "[zrtp_passthru] Setting a-leg inherit_codec=true\n");
5160 				switch_channel_set_variable(o_channel, "inherit_codec", "true");
5161 				if ((x = switch_channel_get_variable(o_channel, "ep_codec_string"))) {
5162 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "[zrtp_passthru] Setting b-leg absolute_codec_string='%s'\n", x);
5163 					switch_channel_set_variable(nchannel, "absolute_codec_string", x);
5164 				}
5165 			}
5166 
5167 			/* SNARK: lets copy this across so we can see if we're the other leg of 3PCC + bypass_media... */
5168 			if (sofia_test_flag(ctech_pvt, TFLAG_3PCC) && (switch_channel_test_flag(o_channel, CF_PROXY_MODE) || switch_channel_test_flag(o_channel, CF_PROXY_MEDIA))) {
5169 				sofia_set_flag(tech_pvt, TFLAG_3PCC_INVITE);
5170 				sofia_set_flag(tech_pvt, TFLAG_LATE_NEGOTIATION);
5171 			} else {
5172 				sofia_clear_flag(tech_pvt, TFLAG_3PCC_INVITE);
5173 			}
5174 		}
5175 
5176 		switch_core_media_check_outgoing_proxy(nsession, session);
5177 
5178 	}
5179 
5180 	goto done;
5181 
5182   error:
5183 	/* gateway pointer lock is really a readlock of the profile so we let the profile release below free that lock if we have a profile */
5184 	if (gateway_ptr && !profile) {
5185 		sofia_reg_release_gateway(gateway_ptr);
5186 	}
5187 
5188 	if (nsession) {
5189 		switch_core_session_destroy(&nsession);
5190 	}
5191 	if (pool) {
5192 		*pool = NULL;
5193 	}
5194   done:
5195 
5196 	if (profile) {
5197 		if (cause == SWITCH_CAUSE_SUCCESS) {
5198 			profile->ob_calls++;
5199 		} else {
5200 			profile->ob_failed_calls++;
5201 		}
5202 		sofia_glue_release_profile(profile);
5203 	}
5204 	return cause;
5205 }
5206 
notify_csta_callback(void * pArg,int argc,char ** argv,char ** columnNames)5207 static int notify_csta_callback(void *pArg, int argc, char **argv, char **columnNames)
5208 {
5209 	nua_handle_t *nh;
5210 	sofia_profile_t *ext_profile = NULL, *profile = (sofia_profile_t *) pArg;
5211 	int i = 0;
5212 	char *user = argv[i++];
5213 	char *host = argv[i++];
5214 	char *contact_in = argv[i++];
5215 	char *profile_name = argv[i++];
5216 	char *call_id = argv[i++];
5217 	char *full_from = argv[i++];
5218 	char *full_to = argv[i++];
5219 	int expires = atoi(argv[i++]);
5220 	char *body = argv[i++];
5221 	char *ct = argv[i++];
5222 	char *id = NULL;
5223 	char *contact;
5224 	sip_cseq_t *cseq = NULL;
5225 	uint32_t callsequence;
5226 	sofia_destination_t *dst = NULL;
5227 	char *route_uri = NULL;
5228 
5229 	time_t epoch_now = switch_epoch_time_now(NULL);
5230 	time_t expires_in = (expires - epoch_now);
5231 	char *extra_headers = switch_mprintf("Subscription-State: active, %d\r\n", expires_in);
5232 
5233 	if (profile_name && strcasecmp(profile_name, profile->name)) {
5234 		if ((ext_profile = sofia_glue_find_profile(profile_name))) {
5235 			profile = ext_profile;
5236 		}
5237 	}
5238 
5239 	id = switch_mprintf("sip:%s@%s", user, host);
5240 	switch_assert(id);
5241 	contact = sofia_glue_get_url_from_contact(contact_in, 1);
5242 
5243 
5244 	dst = sofia_glue_get_destination((char *) contact);
5245 
5246 	if (dst->route_uri) {
5247 		route_uri = sofia_glue_strip_uri(dst->route_uri);
5248 	}
5249 
5250 	callsequence = sofia_presence_get_cseq(profile);
5251 
5252 	//nh = nua_handle(profile->nua, NULL, NUTAG_URL(dst->contact), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), SIPTAG_CONTACT_STR(profile->url), TAG_END());
5253 	nh = nua_handle(profile->nua, NULL, NUTAG_URL(dst->contact), SIPTAG_FROM_STR(full_to), SIPTAG_TO_STR(full_from), SIPTAG_CONTACT_STR(profile->url), TAG_END());
5254 	cseq = sip_cseq_create(nh->nh_home, callsequence, SIP_METHOD_NOTIFY);
5255 
5256 	nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
5257 
5258 	nua_notify(nh, NUTAG_NEWSUB(1),
5259 			   TAG_IF(dst->route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
5260 			   SIPTAG_EVENT_STR("as-feature-event"), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), SIPTAG_CSEQ(cseq),
5261 			   TAG_END());
5262 
5263 
5264 
5265 	switch_safe_free(route_uri);
5266 	sofia_glue_free_destination(dst);
5267 
5268 	free(extra_headers);
5269 	free(id);
5270 	free(contact);
5271 
5272 	if (ext_profile) {
5273 		sofia_glue_release_profile(ext_profile);
5274 	}
5275 
5276 	return 0;
5277 }
5278 
notify_callback(void * pArg,int argc,char ** argv,char ** columnNames)5279 static int notify_callback(void *pArg, int argc, char **argv, char **columnNames)
5280 {
5281 
5282 	nua_handle_t *nh;
5283 	sofia_profile_t *ext_profile = NULL, *profile = (sofia_profile_t *) pArg;
5284 	char *user = argv[0];
5285 	char *host = argv[1];
5286 	char *contact_in = argv[2];
5287 	char *profile_name = argv[3];
5288 	char *ct = argv[4];
5289 	char *es = argv[5];
5290 	char *body = argv[6];
5291 	char *id = NULL;
5292 	char *contact;
5293 	sofia_destination_t *dst = NULL;
5294 	char *route_uri = NULL;
5295 
5296 	if (profile_name && strcasecmp(profile_name, profile->name)) {
5297 		if ((ext_profile = sofia_glue_find_profile(profile_name))) {
5298 			profile = ext_profile;
5299 		}
5300 	}
5301 
5302 	id = switch_mprintf("sip:%s@%s", user, host);
5303 	switch_assert(id);
5304 	contact = sofia_glue_get_url_from_contact(contact_in, 1);
5305 
5306 
5307 	dst = sofia_glue_get_destination((char *) contact);
5308 
5309 	if (dst->route_uri) {
5310 		route_uri = sofia_glue_strip_uri(dst->route_uri);
5311 	}
5312 
5313 	nh = nua_handle(profile->nua, NULL, NUTAG_URL(dst->contact), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), SIPTAG_CONTACT_STR(profile->url), TAG_END());
5314 
5315 	nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
5316 
5317 	nua_notify(nh, NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
5318 			   TAG_IF(dst->route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
5319 			   SIPTAG_EVENT_STR(es), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_END());
5320 
5321 
5322 	switch_safe_free(route_uri);
5323 	sofia_glue_free_destination(dst);
5324 
5325 	free(id);
5326 	free(contact);
5327 
5328 	if (ext_profile) {
5329 		sofia_glue_release_profile(ext_profile);
5330 	}
5331 
5332 	return 0;
5333 }
5334 
general_event_handler(switch_event_t * event)5335 void general_event_handler(switch_event_t *event)
5336 {
5337 	switch (event->event_id) {
5338 	case SWITCH_EVENT_NOTIFY:
5339 		{
5340 			const char *profile_name = switch_event_get_header(event, "profile");
5341 			const char *ct = switch_event_get_header(event, "content-type");
5342 			const char *es = switch_event_get_header(event, "event-string");
5343 			const char *user = switch_event_get_header(event, "user");
5344 			const char *host = switch_event_get_header(event, "host");
5345 			const char *call_id = switch_event_get_header(event, "call-id");
5346 			const char *uuid = switch_event_get_header(event, "uuid");
5347 			const char *body = switch_event_get_body(event);
5348 			const char *to_uri = switch_event_get_header(event, "to-uri");
5349 			const char *from_uri = switch_event_get_header(event, "from-uri");
5350 			const char *extra_headers = switch_event_get_header(event, "extra-headers");
5351 			const char *contact_uri = switch_event_get_header(event, "contact-uri");
5352 			const char *no_sub_state = switch_event_get_header(event, "no-sub-state");
5353 
5354 			sofia_profile_t *profile;
5355 
5356 			if (contact_uri) {
5357 				if (!es) {
5358 					es = "message-summary";
5359 				}
5360 
5361 				if (!ct) {
5362 					ct = "application/simple-message-summary";
5363 				}
5364 
5365 				if (!profile_name) {
5366 					profile_name = "default";
5367 				}
5368 
5369 				if (!(profile = sofia_glue_find_profile(profile_name))) {
5370 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find profile %s\n", profile_name);
5371 					return;
5372 				}
5373 
5374 				if (to_uri && from_uri) {
5375 					sofia_destination_t *dst = NULL;
5376 					nua_handle_t *nh;
5377 					char *route_uri = NULL;
5378 					char *sip_sub_st = NULL;
5379 
5380 					dst = sofia_glue_get_destination((char *) contact_uri);
5381 
5382 					if (dst->route_uri) {
5383 						route_uri = sofia_glue_strip_uri(dst->route_uri);
5384 					}
5385 
5386 					if (zstr(dst->contact)) {
5387 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid contact uri [%s]\n", switch_str_nil(dst->contact));
5388 						sofia_glue_free_destination(dst);
5389 						switch_safe_free(route_uri);
5390 						sofia_glue_release_profile(profile);
5391 						return;
5392 					}
5393 
5394 					nh = nua_handle(profile->nua,
5395 									NULL,
5396 									NUTAG_URL(dst->contact),
5397 									SIPTAG_FROM_STR(from_uri),
5398 									SIPTAG_TO_STR(to_uri),
5399 									SIPTAG_CONTACT_STR(profile->url),
5400 									TAG_END());
5401 
5402 					nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
5403 
5404 					if (!switch_true(no_sub_state)) {
5405 						sip_sub_st = "terminated;reason=noresource";
5406 					}
5407 
5408 					nua_notify(nh,
5409 							   NUTAG_NEWSUB(1), TAG_IF(sip_sub_st, SIPTAG_SUBSCRIPTION_STATE_STR(sip_sub_st)),
5410 							   TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)), TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
5411 							   SIPTAG_EVENT_STR(es), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)),
5412 							   TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
5413 							   TAG_END());
5414 
5415 					switch_safe_free(route_uri);
5416 					sofia_glue_free_destination(dst);
5417 				}
5418 
5419 				sofia_glue_release_profile(profile);
5420 
5421 				return;
5422 			} else if (to_uri || from_uri) {
5423 				if (!es) {
5424 					es = "message-summary";
5425 				}
5426 
5427 				if (!ct) {
5428 					ct = "application/simple-message-summary";
5429 				}
5430 
5431 				if (!profile_name) {
5432 					profile_name = "default";
5433 				}
5434 
5435 				if (!(profile = sofia_glue_find_profile(profile_name))) {
5436 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find profile %s\n", profile_name);
5437 					return;
5438 				}
5439 
5440 				if (to_uri && from_uri) {
5441 					sofia_destination_t *dst = NULL;
5442 					nua_handle_t *nh;
5443 					char *route_uri = NULL;
5444 
5445 					dst = sofia_glue_get_destination((char *) to_uri);
5446 
5447 					if (dst->route_uri) {
5448 						route_uri = sofia_glue_strip_uri(dst->route_uri);
5449 					}
5450 
5451 
5452 					nh = nua_handle(profile->nua,
5453 									NULL,
5454 									NUTAG_URL(to_uri),
5455 									SIPTAG_FROM_STR(from_uri),
5456 									SIPTAG_TO_STR(to_uri),
5457 									SIPTAG_CONTACT_STR(profile->url),
5458 									TAG_END());
5459 
5460 					nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
5461 
5462 					nua_notify(nh,
5463 							   NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
5464 							   TAG_IF(dst->route_uri, NUTAG_PROXY(dst->route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
5465 							   SIPTAG_EVENT_STR(es), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)),
5466 							   TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
5467 							   TAG_END());
5468 
5469 
5470 					switch_safe_free(route_uri);
5471 					sofia_glue_free_destination(dst);
5472 				}
5473 
5474 				sofia_glue_release_profile(profile);
5475 
5476 				return;
5477 			}
5478 
5479 			if (uuid && ct && es) {
5480 				switch_core_session_t *session;
5481 				private_object_t *tech_pvt;
5482 
5483 				if ((session = switch_core_session_locate(uuid))) {
5484 					if ((tech_pvt = switch_core_session_get_private(session))) {
5485 						const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
5486 						nua_notify(tech_pvt->nh,
5487 								   NUTAG_NEWSUB(1), SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
5488 								   SIPTAG_EVENT_STR(es), SIPTAG_CONTENT_TYPE_STR(ct), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)),
5489 								   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
5490 								   TAG_END());
5491 					}
5492 					switch_core_session_rwunlock(session);
5493 				}
5494 			} else if (profile_name && ct && es && user && host && (profile = sofia_glue_find_profile(profile_name))) {
5495 				char *sql;
5496 
5497 				if (call_id) {
5498 					sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,'%q','%q','%q' "
5499 										 "from sip_registrations where call_id='%q'", ct, es, switch_str_nil(body), call_id);
5500 				} else {
5501 					if (!strcasecmp(es, "message-summary")) {
5502 						sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,'%q','%q','%q' "
5503 											 "from sip_registrations where mwi_user='%q' and mwi_host='%q'",
5504 											 ct, es, switch_str_nil(body), switch_str_nil(user), switch_str_nil(host)
5505 							);
5506 					} else {
5507 						sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,'%q','%q','%q' "
5508 											 "from sip_registrations where sip_user='%q' and sip_host='%q'",
5509 											 ct, es, switch_str_nil(body), switch_str_nil(user), switch_str_nil(host)
5510 							);
5511 
5512 					}
5513 				}
5514 
5515 
5516 				switch_mutex_lock(profile->dbh_mutex);
5517 				sofia_glue_execute_sql_callback(profile, NULL, sql, notify_callback, profile);
5518 				switch_mutex_unlock(profile->dbh_mutex);
5519 				sofia_glue_release_profile(profile);
5520 
5521 				free(sql);
5522 			}
5523 
5524 		}
5525 		break;
5526 	case SWITCH_EVENT_PHONE_FEATURE:
5527 		{
5528 			const char *profile_name = switch_event_get_header(event, "profile");
5529 			const char *user = switch_event_get_header(event, "user");
5530 			const char *host = switch_event_get_header(event, "host");
5531 			const char *call_id = switch_event_get_header(event, "call-id");
5532 			const char *csta_event = switch_event_get_header(event, "Feature-Event");
5533 
5534 			char *ct = "application/x-as-feature-event+xml";
5535 			char *ct_m = NULL;
5536 
5537 			sofia_profile_t *profile;
5538 
5539 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Phone Feature NOTIFY\n");
5540 			if (profile_name && user && host && (profile = sofia_glue_find_profile(profile_name))) {
5541 				char *sql;
5542 				switch_stream_handle_t stream = { 0 };
5543 				SWITCH_STANDARD_STREAM(stream);
5544 
5545 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "we have all required vars\n");
5546 
5547 				if (csta_event) {
5548 					if (!strcmp(csta_event, "init")) {
5549 						char *boundary_string = "UniqueFreeSWITCHBoundary";
5550 						switch_stream_handle_t dnd_stream = { 0 };
5551 
5552 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending multipart with DND and CFWD\n");
5553 
5554 						if (switch_event_get_header(event, "forward_immediate")) {
5555 							switch_stream_handle_t fwdi_stream = { 0 };
5556 							SWITCH_STANDARD_STREAM(fwdi_stream);
5557 							write_csta_xml_chunk(event, fwdi_stream, "ForwardingEvent", "forwardImmediate");
5558 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] is %d bytes long\n", (char *)fwdi_stream.data, (int)strlen(fwdi_stream.data));
5559 							stream.write_function(&stream, "--%s\r\nContent-Type: application/x-as-feature-event+xml\r\nContent-Length: %d\r\nContent-ID: <%si@%s>\r\n\r\n%s", boundary_string, strlen(fwdi_stream.data), user, host, fwdi_stream.data);
5560 							switch_safe_free(fwdi_stream.data);
5561 						}
5562 						if (switch_event_get_header(event, "forward_busy")) {
5563 							switch_stream_handle_t fwdb_stream = { 0 };
5564 							SWITCH_STANDARD_STREAM(fwdb_stream);
5565 							write_csta_xml_chunk(event, fwdb_stream, "ForwardingEvent", "forwardBusy");
5566 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] is %d bytes long\n", (char *)fwdb_stream.data, (int)strlen(fwdb_stream.data));
5567 							stream.write_function(&stream, "--%s\r\nContent-Type: application/x-as-feature-event+xml\r\nContent-Length: %d\r\nContent-ID: <%sb@%s>\r\n\r\n%s", boundary_string, strlen(fwdb_stream.data), user, host, fwdb_stream.data);
5568 							switch_safe_free(fwdb_stream.data);
5569 						}
5570 						if (switch_event_get_header(event, "forward_no_answer")) {
5571 							switch_stream_handle_t fwdna_stream = { 0 };
5572 							SWITCH_STANDARD_STREAM(fwdna_stream);
5573 							write_csta_xml_chunk(event, fwdna_stream, "ForwardingEvent", "forwardNoAns");
5574 							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] is %d bytes long\n", (char *)fwdna_stream.data, (int)strlen(fwdna_stream.data));
5575 							stream.write_function(&stream, "--%s\r\nContent-Type: application/x-as-feature-event+xml\r\nContent-Length: %d\r\nContent-ID: <%sn@%s>\r\n\r\n%s", boundary_string, strlen(fwdna_stream.data), user, host, fwdna_stream.data);
5576 							switch_safe_free(fwdna_stream.data);
5577 						}
5578 
5579 						SWITCH_STANDARD_STREAM(dnd_stream);
5580 						write_csta_xml_chunk(event, dnd_stream, "DoNotDisturbEvent", NULL);
5581 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[%s] is %d bytes long\n", (char *)dnd_stream.data, (int)strlen(dnd_stream.data));
5582 						stream.write_function(&stream, "--%s\r\nContent-Type: application/x-as-feature-event+xml\r\nContent-Length: %d\r\nContent-ID: <%sd@%s>\r\n\r\n%s", boundary_string, strlen(dnd_stream.data), user, host, dnd_stream.data);
5583 						switch_safe_free(dnd_stream.data);
5584 
5585 						stream.write_function(&stream, "--%s--\r\n", boundary_string);
5586 
5587 						ct_m = switch_mprintf("multipart/mixed; boundary=\"%s\"", boundary_string);
5588 						ct = ct_m;
5589 					} else {
5590 						char *fwd_type = NULL;
5591 
5592 						if (switch_event_get_header(event, "forward_immediate")) {
5593 							fwd_type = "forwardImmediate";
5594 						} else if (switch_event_get_header(event, "forward_busy")) {
5595 							fwd_type = "forwardBusy";
5596 						} else if (switch_event_get_header(event, "forward_no_answer")) {
5597 							fwd_type = "forwardNoAns";
5598 						}
5599 
5600 						// this will need some work to handle the different types of forwarding events
5601 						write_csta_xml_chunk(event, stream, csta_event, fwd_type);
5602 					}
5603 				}
5604 
5605 				if (call_id) {
5606 					sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,call_id,full_from,full_to,expires,'%q', '%q' "
5607 										 "from sip_subscriptions where event='as-feature-event' and call_id='%q'", stream.data, ct, call_id);
5608 				} else {
5609 					sql = switch_mprintf("select sip_user,sip_host,contact,profile_name,call_id,full_from,full_to,expires,'%q', '%q' "
5610 										 "from sip_subscriptions where event='as-feature-event' and sip_user='%q' and sip_host='%q'", stream.data, ct, switch_str_nil(user), switch_str_nil(host)
5611 										 );
5612 				}
5613 
5614 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query: %s\n", sql);
5615 				switch_safe_free(stream.data);
5616 				switch_mutex_lock(profile->ireg_mutex);
5617 				sofia_glue_execute_sql_callback(profile, NULL, sql, notify_csta_callback, profile);
5618 				switch_mutex_unlock(profile->ireg_mutex);
5619 				sofia_glue_release_profile(profile);
5620 
5621 				free(sql);
5622 			} else {
5623 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "missing something\n");
5624 			}
5625 			switch_safe_free(ct_m);
5626 		}
5627 		break;
5628 	case SWITCH_EVENT_SEND_MESSAGE:
5629 		{
5630 			const char *profile_name = switch_event_get_header(event, "profile");
5631 			const char *ct = switch_event_get_header(event, "content-type");
5632 			const char *user = switch_event_get_header(event, "user");
5633 			const char *host = switch_event_get_header(event, "host");
5634 			const char *subject = switch_event_get_header(event, "subject");
5635 			const char *uuid = switch_event_get_header(event, "uuid");
5636 			const char *body = switch_event_get_body(event);
5637 
5638 			sofia_profile_t *profile;
5639 			nua_handle_t *nh;
5640 
5641 			if (ct && user && host) {
5642 				char *id = NULL;
5643 				char *contact, *p;
5644 				switch_console_callback_match_t *list = NULL;
5645 				switch_console_callback_match_node_t *m;
5646 
5647 				if (!profile_name || !(profile = sofia_glue_find_profile(profile_name))) {
5648 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find profile %s\n", profile_name);
5649 					return;
5650 				}
5651 
5652 				if (!(list = sofia_reg_find_reg_url_multi(profile, user, host))) {
5653 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find registered user %s@%s\n", user, host);
5654 					sofia_glue_release_profile(profile);
5655 					return;
5656 				}
5657 
5658 				id = switch_mprintf("sip:%s@%s", user, host);
5659 
5660 				switch_assert(id);
5661 
5662 				for (m = list->head; m; m = m->next) {
5663 					contact = sofia_glue_get_url_from_contact(m->val, 0);
5664 
5665 					if ((p = strstr(contact, ";fs_"))) {
5666 						*p = '\0';
5667 					}
5668 
5669 					nh = nua_handle(profile->nua,
5670 									NULL, NUTAG_URL(contact), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), SIPTAG_CONTACT_STR(profile->url), TAG_END());
5671 
5672 					nua_message(nh, NUTAG_NEWSUB(1), SIPTAG_CONTENT_TYPE_STR(ct),
5673 								TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_IF(!zstr(subject), SIPTAG_SUBJECT_STR(subject)), TAG_END());
5674 				}
5675 
5676 				free(id);
5677 				switch_console_free_matches(&list);
5678 
5679 				sofia_glue_release_profile(profile);
5680 			} else if (uuid && ct) {
5681 				switch_core_session_t *session;
5682 				private_object_t *tech_pvt;
5683 
5684 				if ((session = switch_core_session_locate(uuid))) {
5685 					if ((tech_pvt = switch_core_session_get_private(session))) {
5686 						const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
5687 
5688 						nua_message(tech_pvt->nh,
5689 									SIPTAG_CONTENT_TYPE_STR(ct), SIPTAG_PAYLOAD_STR(body),
5690 									TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_IF(!zstr(subject), SIPTAG_SUBJECT_STR(subject)),
5691 									TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
5692 									TAG_END());
5693 					}
5694 					switch_core_session_rwunlock(session);
5695 				}
5696 			}
5697 		}
5698 		break;
5699 	case SWITCH_EVENT_SEND_INFO:
5700 		{
5701 			const char *profile_name = switch_event_get_header(event, "profile");
5702 			const char *ct = switch_event_get_header(event, "content-type");
5703 			const char *cd = switch_event_get_header(event, "content-disposition");
5704 			const char *to_uri = switch_event_get_header(event, "to-uri");
5705 			const char *local_user_full = switch_event_get_header(event, "local-user");
5706 			const char *from_uri = switch_event_get_header(event, "from-uri");
5707 			const char *call_info = switch_event_get_header(event, "call-info");
5708 			const char *alert_info = switch_event_get_header(event, "alert-info");
5709 			const char *call_id = switch_event_get_header(event, "call-id");
5710 			const char *body = switch_event_get_body(event);
5711 			sofia_profile_t *profile = NULL;
5712 			nua_handle_t *nh;
5713 			char *local_dup = NULL;
5714 			char *local_user, *local_host;
5715 			char buf[1024] = "";
5716 			char *p;
5717 
5718 			if (!profile_name) {
5719 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Profile Name\n");
5720 				goto done;
5721 			}
5722 
5723 			if (!call_id && !to_uri && !local_user_full) {
5724 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing To-URI header\n");
5725 				goto done;
5726 			}
5727 
5728 			if (!call_id && !from_uri) {
5729 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing From-URI header\n");
5730 				goto done;
5731 			}
5732 
5733 
5734 			if (!(profile = sofia_glue_find_profile(profile_name))) {
5735 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find profile %s\n", profile_name);
5736 				goto done;
5737 			}
5738 
5739 			if (call_id) {
5740 				nh = nua_handle_by_call_id(profile->nua, call_id);
5741 
5742 				if (!nh) {
5743 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Call-ID %s\n", call_id);
5744 					goto done;
5745 				}
5746 			} else {
5747 				if (local_user_full) {
5748 					local_dup = strdup(local_user_full);
5749 					switch_assert(local_dup);
5750 					local_user = local_dup;
5751 					if ((local_host = strchr(local_user, '@'))) {
5752 						*local_host++ = '\0';
5753 					}
5754 
5755 					if (!local_host || !sofia_reg_find_reg_url(profile, local_user, local_host, buf, sizeof(buf))) {
5756 						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find local user\n");
5757 						goto done;
5758 					}
5759 
5760 					to_uri = sofia_glue_get_url_from_contact(buf, 0);
5761 
5762 					if ((p = strstr(to_uri, ";fs_"))) {
5763 						*p = '\0';
5764 					}
5765 
5766 				}
5767 
5768 				nh = nua_handle(profile->nua,
5769 								NULL, NUTAG_URL(to_uri), SIPTAG_FROM_STR(from_uri), SIPTAG_TO_STR(to_uri), SIPTAG_CONTACT_STR(profile->url), TAG_END());
5770 
5771 				nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
5772 			}
5773 
5774 			nua_info(nh,
5775 					 TAG_IF(ct, SIPTAG_CONTENT_TYPE_STR(ct)),
5776 					 TAG_IF(cd, SIPTAG_CONTENT_DISPOSITION_STR(cd)),
5777 					 TAG_IF(alert_info, SIPTAG_ALERT_INFO_STR(alert_info)),
5778 					 TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), TAG_IF(!zstr(body), SIPTAG_PAYLOAD_STR(body)), TAG_END());
5779 
5780 			if (call_id && nh) {
5781 				nua_handle_unref(nh);
5782 			}
5783 
5784 		  done:
5785 
5786 			if (profile) {
5787 				sofia_glue_release_profile(profile);
5788 			}
5789 
5790 			switch_safe_free(local_dup);
5791 
5792 		}
5793 		break;
5794 	case SWITCH_EVENT_TRAP:
5795 		{
5796 			const char *cond = switch_event_get_header(event, "condition");
5797 			switch_hash_index_t *hi;
5798 			const void *var;
5799 			void *val;
5800 			sofia_profile_t *profile;
5801 
5802 			if (zstr(cond)) {
5803 				cond = "";
5804 			}
5805 
5806 			if (!strcmp(cond, "network-external-address-change") && mod_sofia_globals.auto_restart) {
5807 				const char *old_ip4 = switch_event_get_header_nil(event, "network-external-address-previous-v4");
5808 				const char *new_ip4 = switch_event_get_header_nil(event, "network-external-address-change-v4");
5809 
5810 				switch_mutex_lock(mod_sofia_globals.hash_mutex);
5811 				if (mod_sofia_globals.profile_hash && !zstr(old_ip4) && !zstr(new_ip4)) {
5812 					for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
5813 						switch_core_hash_this(hi, &var, NULL, &val);
5814 
5815 						if ((profile = (sofia_profile_t *) val)) {
5816 							if (!zstr(profile->extsipip) && !strcmp(profile->extsipip, old_ip4)) {
5817 								profile->extsipip = switch_core_strdup(profile->pool, new_ip4);
5818 							}
5819 
5820 							if (!zstr(profile->extrtpip) && !strcmp(profile->extrtpip, old_ip4)) {
5821 								profile->extrtpip = switch_core_strdup(profile->pool, new_ip4);
5822 							}
5823 						}
5824 					}
5825 				}
5826 				switch_mutex_unlock(mod_sofia_globals.hash_mutex);
5827 				sofia_glue_restart_all_profiles();
5828 			} else if (!strcmp(cond, "network-address-change") && mod_sofia_globals.auto_restart) {
5829 				const char *old_ip4 = switch_event_get_header_nil(event, "network-address-previous-v4");
5830 				const char *new_ip4 = switch_event_get_header_nil(event, "network-address-change-v4");
5831 				const char *old_ip6 = switch_event_get_header_nil(event, "network-address-previous-v6");
5832 				const char *new_ip6 = switch_event_get_header_nil(event, "network-address-change-v6");
5833 
5834 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "EVENT_TRAP: IP change detected\n");
5835 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "IP change detected [%s]->[%s] [%s]->[%s]\n", old_ip4, new_ip4, old_ip6, new_ip6);
5836 
5837 				snprintf(mod_sofia_globals.guess_ip, sizeof(mod_sofia_globals.guess_ip), "%s", new_ip4);
5838 
5839 				switch_mutex_lock(mod_sofia_globals.hash_mutex);
5840 				if (mod_sofia_globals.profile_hash) {
5841 					for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
5842 						int rb = 0;
5843 						uint32_t x = 0;
5844 						switch_core_hash_this(hi, &var, NULL, &val);
5845 						if ((profile = (sofia_profile_t *) val) && profile->auto_restart) {
5846 							if (!strcmp(profile->sipip, old_ip4)) {
5847 								profile->sipip = switch_core_strdup(profile->pool, new_ip4);
5848 								rb++;
5849 							}
5850 
5851 							for (x = 0; x < profile->rtpip_index; x++) {
5852 
5853 								if (!strcmp(profile->rtpip[x], old_ip4)) {
5854 									profile->rtpip[x] = switch_core_strdup(profile->pool, new_ip4);
5855 									rb++;
5856 								}
5857 
5858 								if (!strcmp(profile->rtpip[x], old_ip6)) {
5859 									profile->rtpip6[x] = switch_core_strdup(profile->pool, new_ip6);
5860 									rb++;
5861 								}
5862 							}
5863 
5864 
5865 							if (!strcmp(profile->sipip, old_ip6)) {
5866 								profile->sipip = switch_core_strdup(profile->pool, new_ip6);
5867 								rb++;
5868 							}
5869 
5870 							if (rb) {
5871 								sofia_set_pflag_locked(profile, PFLAG_RESPAWN);
5872 								sofia_clear_pflag_locked(profile, PFLAG_RUNNING);
5873 							}
5874 						}
5875 					}
5876 				}
5877 				switch_mutex_unlock(mod_sofia_globals.hash_mutex);
5878 			}
5879 
5880 		}
5881 		break;
5882 	default:
5883 		break;
5884 	}
5885 }
5886 
general_queue_event_handler(switch_event_t * event)5887 static void general_queue_event_handler(switch_event_t *event)
5888 {
5889 	switch_event_t *dup;
5890 	switch_event_dup(&dup, event);
5891 	switch_queue_push(mod_sofia_globals.general_event_queue, dup);
5892 }
5893 
5894 
write_csta_xml_chunk(switch_event_t * event,switch_stream_handle_t stream,const char * csta_event,char * fwdtype)5895 void write_csta_xml_chunk(switch_event_t *event, switch_stream_handle_t stream, const char *csta_event, char *fwdtype)
5896 {
5897 	const char *device = switch_event_get_header(event, "device");
5898 
5899 	switch_assert(csta_event);
5900 
5901 	stream.write_function(&stream, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<%s xmlns=\"http://www.ecma-international.org/standards/ecma-323/csta/ed3\">\n", csta_event);
5902 
5903 	if (device) {
5904 		stream.write_function(&stream, "  <device>%s</device>\n", device);
5905 	}
5906 
5907 	if (!strcmp(csta_event, "DoNotDisturbEvent")) {
5908 		const char *dndstatus = switch_event_get_header(event, "doNotDisturbOn");
5909 
5910 		if (dndstatus) {
5911 			stream.write_function(&stream, "  <doNotDisturbOn>%s</doNotDisturbOn>\n", dndstatus);
5912 		}
5913 	} else if(!strcmp(csta_event, "ForwardingEvent")) {
5914 		const char *fwdstatus = NULL;
5915 		const char *fwdto = NULL;
5916 		const char *ringcount = NULL;
5917 
5918 		if (fwdtype && !zstr(fwdtype)) {
5919 			if (!strcmp("forwardImmediate", fwdtype)) {
5920 				fwdto = switch_event_get_header(event, "forward_immediate");
5921 				fwdstatus = switch_event_get_header(event, "forward_immediate_enabled");
5922 			} else if (!strcmp("forwardBusy", fwdtype)) {
5923 				fwdto = switch_event_get_header(event, "forward_busy");
5924 				fwdstatus = switch_event_get_header(event, "forward_busy_enabled");
5925 			} else if (!strcmp("forwardNoAns", fwdtype)) {
5926 				fwdto = switch_event_get_header(event, "forward_no_answer");
5927 				fwdstatus = switch_event_get_header(event, "forward_no_answer_enabled");
5928 				ringcount = switch_event_get_header(event, "ringCount");
5929 			}
5930 
5931 			stream.write_function(&stream, "  <forwardingType>%s</forwardingType>\n", fwdtype);
5932 			if (fwdstatus) {
5933 				stream.write_function(&stream, "  <forwardStatus>%s</forwardStatus>\n", fwdstatus);
5934 			}
5935 			if (fwdto) {
5936 				stream.write_function(&stream, "  <forwardTo>%s</forwardTo>\n", fwdto);
5937 			}
5938 			if (ringcount) {
5939 				stream.write_function(&stream, "  <ringCount>%s</ringCount>\n", ringcount);
5940 			}
5941 		}
5942 	}
5943 
5944 	stream.write_function(&stream, "</%s>\n", csta_event);
5945 }
5946 
list_profiles_full(const char * line,const char * cursor,switch_console_callback_match_t ** matches,switch_bool_t show_aliases)5947 switch_status_t list_profiles_full(const char *line, const char *cursor, switch_console_callback_match_t **matches, switch_bool_t show_aliases)
5948 {
5949 	sofia_profile_t *profile = NULL;
5950 	switch_hash_index_t *hi;
5951 	void *val;
5952 	const void *vvar;
5953 	switch_console_callback_match_t *my_matches = NULL;
5954 	switch_status_t status = SWITCH_STATUS_FALSE;
5955 
5956 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
5957 	for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
5958 		switch_core_hash_this(hi, &vvar, NULL, &val);
5959 
5960 		profile = (sofia_profile_t *) val;
5961 		if (!show_aliases && strcmp((char *)vvar, profile->name)) {
5962 			continue;
5963 		}
5964 
5965 		if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
5966 			switch_console_push_match(&my_matches, (const char *) vvar);
5967 		}
5968 	}
5969 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
5970 
5971 	if (my_matches) {
5972 		*matches = my_matches;
5973 		status = SWITCH_STATUS_SUCCESS;
5974 	}
5975 
5976 
5977 	return status;
5978 }
5979 
list_profiles(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5980 switch_status_t list_profiles(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5981 {
5982 	return list_profiles_full(line, cursor, matches, SWITCH_TRUE);
5983 }
5984 
list_gateways(const char * line,const char * cursor,switch_console_callback_match_t ** matches)5985 static switch_status_t list_gateways(const char *line, const char *cursor, switch_console_callback_match_t **matches)
5986 {
5987 	sofia_profile_t *profile = NULL;
5988 	switch_hash_index_t *hi;
5989 	void *val;
5990 	const void *vvar;
5991 	switch_console_callback_match_t *my_matches = NULL;
5992 	switch_status_t status = SWITCH_STATUS_FALSE;
5993 
5994 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
5995 	for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
5996 		switch_core_hash_this(hi, &vvar, NULL, &val);
5997 		profile = (sofia_profile_t *) val;
5998 		if (sofia_test_pflag(profile, PFLAG_RUNNING)) {
5999 			sofia_gateway_t *gp;
6000 			switch_mutex_lock(profile->gw_mutex);
6001 			for (gp = profile->gateways; gp; gp = gp->next) {
6002 				switch_console_push_match(&my_matches, gp->name);
6003 			}
6004 			switch_mutex_unlock(profile->gw_mutex);
6005 		}
6006 	}
6007 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
6008 
6009 	if (my_matches) {
6010 		*matches = my_matches;
6011 		status = SWITCH_STATUS_SUCCESS;
6012 	}
6013 
6014 	return status;
6015 }
6016 
6017 
list_profile_gateway(const char * line,const char * cursor,switch_console_callback_match_t ** matches)6018 static switch_status_t list_profile_gateway(const char *line, const char *cursor, switch_console_callback_match_t **matches)
6019 {
6020 	sofia_profile_t *profile = NULL;
6021 	switch_console_callback_match_t *my_matches = NULL;
6022 	switch_status_t status = SWITCH_STATUS_FALSE;
6023 	char *dup = NULL;
6024 	//int argc;
6025 	char *argv[4] = { 0 };
6026 
6027 	if (zstr(line)) {
6028 		return SWITCH_STATUS_FALSE;
6029 	}
6030 
6031 	dup = strdup(line);
6032 	switch_split(dup, ' ', argv);
6033 
6034 	if (zstr(argv[2]) || !strcmp(argv[2], " ")) {
6035 		goto end;
6036 	}
6037 
6038 	if ((profile = sofia_glue_find_profile(argv[2]))) {
6039 		sofia_gateway_t *gp;
6040 		for (gp = profile->gateways; gp; gp = gp->next) {
6041 			switch_console_push_match(&my_matches, gp->name);
6042 		}
6043 		sofia_glue_release_profile(profile);
6044 	}
6045 
6046 	if (my_matches) {
6047 		*matches = my_matches;
6048 		status = SWITCH_STATUS_SUCCESS;
6049 	}
6050 
6051   end:
6052 
6053 	switch_safe_free(dup);
6054 
6055 	return status;
6056 }
6057 
SWITCH_STANDARD_APP(sofia_sla_function)6058 SWITCH_STANDARD_APP(sofia_sla_function)
6059 {
6060 	private_object_t *tech_pvt;
6061 	switch_core_session_t *bargee_session;
6062 	switch_channel_t *channel = switch_core_session_get_channel(session);
6063 
6064 	if (zstr(data)) {
6065 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Usage: <uuid>\n");
6066 		return;
6067 	}
6068 
6069 	switch_channel_answer(channel);
6070 
6071 	if ((bargee_session = switch_core_session_locate((char *)data))) {
6072 		if (bargee_session == session) {
6073 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "BARGE: %s (cannot barge on myself)\n", (char *) data);
6074 		} else {
6075 
6076 			if (switch_core_session_check_interface(bargee_session, sofia_endpoint_interface)) {
6077 				tech_pvt = switch_core_session_get_private(bargee_session);
6078 				switch_channel_clear_flag(tech_pvt->channel, CF_SLA_BARGING);
6079 				switch_channel_set_flag(tech_pvt->channel, CF_SLA_BARGE);
6080 				switch_ivr_transfer_variable(bargee_session, session, SWITCH_SIGNAL_BOND_VARIABLE);
6081 			}
6082 
6083 			if (switch_core_session_check_interface(session, sofia_endpoint_interface)) {
6084 				tech_pvt = switch_core_session_get_private(session);
6085 				switch_channel_set_flag(tech_pvt->channel, CF_SLA_BARGING);
6086 			}
6087 
6088 			switch_channel_set_variable(channel, "sip_barging_uuid", (char *)data);
6089 		}
6090 
6091 		switch_core_session_rwunlock(bargee_session);
6092 	}
6093 
6094 	switch_channel_execute_on(channel, "execute_on_sip_barge");
6095 
6096 	switch_ivr_eavesdrop_session(session, data, NULL, ED_MUX_READ | ED_MUX_WRITE | ED_COPY_DISPLAY);
6097 }
6098 
6099 
SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)6100 SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
6101 {
6102 	switch_chat_interface_t *chat_interface;
6103 	switch_api_interface_t *api_interface;
6104 	switch_management_interface_t *management_interface;
6105 	switch_application_interface_t *app_interface;
6106 	struct in_addr in;
6107 	switch_status_t status;
6108 
6109 	memset(&mod_sofia_globals, 0, sizeof(mod_sofia_globals));
6110 	mod_sofia_globals.destroy_private.destroy_nh = 1;
6111 	mod_sofia_globals.destroy_private.is_static = 1;
6112 	mod_sofia_globals.keep_private.is_static = 1;
6113 	mod_sofia_globals.pool = pool;
6114 	switch_mutex_init(&mod_sofia_globals.mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool);
6115 	switch_core_hash_init(&mod_sofia_globals.profile_hash);
6116 	switch_core_hash_init(&mod_sofia_globals.gateway_hash);
6117 	switch_mutex_init(&mod_sofia_globals.hash_mutex, SWITCH_MUTEX_NESTED, mod_sofia_globals.pool);
6118 
6119 	if (switch_event_reserve_subclass(MY_EVENT_NOTIFY_REFER) != SWITCH_STATUS_SUCCESS) {
6120 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_NOTIFY_REFER);
6121 		switch_goto_status(SWITCH_STATUS_TERM, err);
6122 	}
6123 
6124 	if (switch_event_reserve_subclass(MY_EVENT_NOTIFY_WATCHED_HEADER) != SWITCH_STATUS_SUCCESS) {
6125 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_NOTIFY_WATCHED_HEADER);
6126 		switch_goto_status(SWITCH_STATUS_TERM, err);
6127 	}
6128 
6129 	if (switch_event_reserve_subclass(MY_EVENT_UNREGISTER) != SWITCH_STATUS_SUCCESS) {
6130 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_UNREGISTER);
6131 		switch_goto_status(SWITCH_STATUS_TERM, err);
6132 	}
6133 
6134 	if (switch_event_reserve_subclass(MY_EVENT_PROFILE_START) != SWITCH_STATUS_SUCCESS) {
6135 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_PROFILE_START);
6136 		switch_goto_status(SWITCH_STATUS_TERM, err);
6137 	}
6138 
6139 	if (switch_event_reserve_subclass(MY_EVENT_REINVITE) != SWITCH_STATUS_SUCCESS) {
6140 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REINVITE);
6141 		switch_goto_status(SWITCH_STATUS_TERM, err);
6142 	}
6143 
6144 	if (switch_event_reserve_subclass(MY_EVENT_REPLACED) != SWITCH_STATUS_SUCCESS) {
6145 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REPLACED);
6146 		switch_goto_status(SWITCH_STATUS_TERM, err);
6147 	}
6148 
6149 	if (switch_event_reserve_subclass(MY_EVENT_TRANSFEROR) != SWITCH_STATUS_SUCCESS) {
6150 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_TRANSFEROR);
6151 		switch_goto_status(SWITCH_STATUS_TERM, err);
6152 	}
6153 
6154 	if (switch_event_reserve_subclass(MY_EVENT_TRANSFEREE) != SWITCH_STATUS_SUCCESS) {
6155 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_TRANSFEREE);
6156 		switch_goto_status(SWITCH_STATUS_TERM, err);
6157 	}
6158 
6159 	if (switch_event_reserve_subclass(MY_EVENT_ERROR) != SWITCH_STATUS_SUCCESS) {
6160 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_ERROR);
6161 		switch_goto_status(SWITCH_STATUS_TERM, err);
6162 	}
6163 
6164 	if (switch_event_reserve_subclass(MY_EVENT_INTERCEPTED) != SWITCH_STATUS_SUCCESS) {
6165 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_INTERCEPTED);
6166 		switch_goto_status(SWITCH_STATUS_TERM, err);
6167 	}
6168 
6169 	if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_STATE) != SWITCH_STATUS_SUCCESS) {
6170 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_STATE);
6171 		switch_goto_status(SWITCH_STATUS_TERM, err);
6172 	}
6173 
6174 	if (switch_event_reserve_subclass(MY_EVENT_SIP_USER_STATE) != SWITCH_STATUS_SUCCESS) {
6175 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_SIP_USER_STATE);
6176 		switch_goto_status(SWITCH_STATUS_TERM, err);
6177 	}
6178 
6179 	if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_DEL) != SWITCH_STATUS_SUCCESS) {
6180 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_DEL);
6181 		switch_goto_status(SWITCH_STATUS_TERM, err);
6182 	}
6183 
6184 	if (switch_event_reserve_subclass(MY_EVENT_EXPIRE) != SWITCH_STATUS_SUCCESS) {
6185 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_EXPIRE);
6186 		switch_goto_status(SWITCH_STATUS_TERM, err);
6187 	}
6188 
6189 	if (switch_event_reserve_subclass(MY_EVENT_REGISTER_ATTEMPT) != SWITCH_STATUS_SUCCESS) {
6190 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER_ATTEMPT);
6191 		switch_goto_status(SWITCH_STATUS_TERM, err);
6192 	}
6193 
6194 	if (switch_event_reserve_subclass(MY_EVENT_REGISTER_FAILURE) != SWITCH_STATUS_SUCCESS) {
6195 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER_FAILURE);
6196 		switch_goto_status(SWITCH_STATUS_TERM, err);
6197 	}
6198 
6199 	if (switch_event_reserve_subclass(MY_EVENT_PRE_REGISTER) != SWITCH_STATUS_SUCCESS) {
6200 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_PRE_REGISTER);
6201 		switch_goto_status(SWITCH_STATUS_TERM, err);
6202 	}
6203 
6204 	if (switch_event_reserve_subclass(MY_EVENT_REGISTER) != SWITCH_STATUS_SUCCESS) {
6205 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_REGISTER);
6206 		switch_goto_status(SWITCH_STATUS_TERM, err);
6207 	}
6208 
6209 	if (switch_event_reserve_subclass(MY_EVENT_GATEWAY_ADD) != SWITCH_STATUS_SUCCESS) {
6210 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_GATEWAY_ADD);
6211 		switch_goto_status(SWITCH_STATUS_TERM, err);
6212 	}
6213 
6214 	if (switch_event_reserve_subclass(MY_EVENT_BYE_RESPONSE) != SWITCH_STATUS_SUCCESS) {
6215 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", MY_EVENT_BYE_RESPONSE);
6216 		switch_goto_status(SWITCH_STATUS_TERM, err);
6217 	}
6218 
6219 	switch_find_local_ip(mod_sofia_globals.guess_ip, sizeof(mod_sofia_globals.guess_ip), &mod_sofia_globals.guess_mask, AF_INET);
6220 	in.s_addr = mod_sofia_globals.guess_mask;
6221 	switch_set_string(mod_sofia_globals.guess_mask_str, inet_ntoa(in));
6222 
6223 	strcpy(mod_sofia_globals.hostname, switch_core_get_switchname());
6224 
6225 	switch_mutex_lock(mod_sofia_globals.mutex);
6226 	mod_sofia_globals.running = 1;
6227 	switch_mutex_unlock(mod_sofia_globals.mutex);
6228 
6229 	mod_sofia_globals.auto_nat = (switch_nat_get_type() ? 1 : 0);
6230 
6231 	switch_queue_create(&mod_sofia_globals.presence_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
6232 	switch_queue_create(&mod_sofia_globals.general_event_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
6233 
6234 	mod_sofia_globals.cpu_count = switch_core_cpu_count();
6235 	mod_sofia_globals.max_msg_queues = (mod_sofia_globals.cpu_count / 2) + 1;
6236 	if (mod_sofia_globals.max_msg_queues < 2) {
6237 		mod_sofia_globals.max_msg_queues = 2;
6238 	}
6239 
6240 	if (mod_sofia_globals.max_msg_queues > SOFIA_MAX_MSG_QUEUE) {
6241 		mod_sofia_globals.max_msg_queues = SOFIA_MAX_MSG_QUEUE;
6242 	}
6243 
6244 	switch_queue_create(&mod_sofia_globals.msg_queue, SOFIA_MSG_QUEUE_SIZE * mod_sofia_globals.max_msg_queues, mod_sofia_globals.pool);
6245 
6246 	/* start one message thread */
6247 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Starting initial message thread.\n");
6248 
6249 
6250 	if (sofia_init() != SWITCH_STATUS_SUCCESS) {
6251 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6252 		return SWITCH_STATUS_GENERR;
6253 	}
6254 
6255 	if (config_sofia(SOFIA_CONFIG_LOAD, NULL) != SWITCH_STATUS_SUCCESS) {
6256 		mod_sofia_globals.running = 0;
6257 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6258 		return SWITCH_STATUS_GENERR;
6259 	}
6260 
6261 	sofia_msg_thread_start(0);
6262 
6263 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for profiles to start\n");
6264 	switch_yield(1500000);
6265 
6266 	if (switch_event_bind(modname, SWITCH_EVENT_CUSTOM, MULTICAST_EVENT, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6267 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6268 		switch_goto_status(SWITCH_STATUS_TERM, err);
6269 	}
6270 
6271 	if (switch_event_bind(modname, SWITCH_EVENT_CONFERENCE_DATA, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6272 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6273 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6274 		return SWITCH_STATUS_GENERR;
6275 	}
6276 
6277 	if (switch_event_bind(modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6278 
6279 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6280 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6281 		return SWITCH_STATUS_GENERR;
6282 	}
6283 
6284 	if (switch_event_bind(modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6285 
6286 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6287 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6288 		return SWITCH_STATUS_GENERR;
6289 	}
6290 
6291 	if (switch_event_bind(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6292 
6293 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6294 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6295 		return SWITCH_STATUS_GENERR;
6296 	}
6297 
6298 	if (switch_event_bind(modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6299 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6300 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6301 		return SWITCH_STATUS_GENERR;
6302 	}
6303 
6304 	if (switch_event_bind(modname, SWITCH_EVENT_MESSAGE_WAITING, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6305 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6306 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6307 		return SWITCH_STATUS_GENERR;
6308 	}
6309 
6310 	if (switch_event_bind(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6311 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6312 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6313 		return SWITCH_STATUS_GENERR;
6314 	}
6315 
6316 	if (switch_event_bind(modname, SWITCH_EVENT_NOTIFY, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6317 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6318 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6319 		return SWITCH_STATUS_GENERR;
6320 	}
6321 
6322 	if (switch_event_bind(modname, SWITCH_EVENT_PHONE_FEATURE, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6323 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6324 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6325 		return SWITCH_STATUS_GENERR;
6326 	}
6327 
6328 	if (switch_event_bind(modname, SWITCH_EVENT_SEND_MESSAGE, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6329 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6330 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6331 		return SWITCH_STATUS_GENERR;
6332 	}
6333 
6334 	if (switch_event_bind(modname, SWITCH_EVENT_SEND_INFO, SWITCH_EVENT_SUBCLASS_ANY, general_queue_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
6335 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
6336 		switch_goto_status(SWITCH_STATUS_GENERR, err);
6337 		return SWITCH_STATUS_GENERR;
6338 	}
6339 
6340 	/* connect my internal structure to the blank pointer passed to me */
6341 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
6342 	sofia_endpoint_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
6343 	sofia_endpoint_interface->interface_name = "sofia";
6344 	sofia_endpoint_interface->io_routines = &sofia_io_routines;
6345 	sofia_endpoint_interface->state_handler = &sofia_event_handlers;
6346 	sofia_endpoint_interface->recover_callback = sofia_recover_callback;
6347 
6348 	management_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_MANAGEMENT_INTERFACE);
6349 	management_interface->relative_oid = "1001";
6350 	management_interface->management_function = sofia_manage;
6351 
6352 	add_sofia_json_apis(module_interface);
6353 
6354 	SWITCH_ADD_APP(app_interface, "sofia_sla", "private sofia sla function",
6355 				   "private sofia sla function", sofia_sla_function, "<uuid>", SAF_NONE);
6356 
6357 
6358 	SWITCH_ADD_API(api_interface, "sofia", "Sofia Controls", sofia_function, "<cmd> <args>");
6359 	SWITCH_ADD_API(api_interface, "sofia_gateway_data", "Get data from a sofia gateway", sofia_gateway_data_function, "<gateway_name> [ivar|ovar|var] <name>");
6360 	switch_console_set_complete("add sofia ::[help:status");
6361 	switch_console_set_complete("add sofia status profile ::sofia::list_profiles reg");
6362 	switch_console_set_complete("add sofia status gateway ::sofia::list_gateways");
6363 
6364 	switch_console_set_complete("add sofia loglevel ::[all:default:tport:iptsec:nea:nta:nth_client:nth_server:nua:soa:sresolv:stun ::[0:1:2:3:4:5:6:7:8:9");
6365 	switch_console_set_complete("add sofia tracelevel ::[console:alert:crit:err:warning:notice:info:debug");
6366 
6367 	switch_console_set_complete("add sofia global ::[siptrace::standby::capture::watchdog ::[on:off");
6368 	switch_console_set_complete("add sofia global debug ::[presence:sla:none");
6369 
6370 	switch_console_set_complete("add sofia profile restart all");
6371 	switch_console_set_complete("add sofia profile ::sofia::list_profiles ::[start:rescan:restart:check_sync");
6372 	switch_console_set_complete("add sofia profile ::sofia::list_profiles stop wait");
6373 	switch_console_set_complete("add sofia profile ::sofia::list_profiles flush_inbound_reg reboot");
6374 	switch_console_set_complete("add sofia profile ::sofia::list_profiles ::[register:unregister all");
6375 	switch_console_set_complete("add sofia profile ::sofia::list_profiles ::[register:unregister:killgw:startgw ::sofia::list_profile_gateway");
6376 	switch_console_set_complete("add sofia profile ::sofia::list_profiles killgw _all_");
6377 	switch_console_set_complete("add sofia profile ::sofia::list_profiles startgw _all_");
6378 	switch_console_set_complete("add sofia profile ::sofia::list_profiles ::[siptrace:capture:watchdog ::[on:off");
6379 	switch_console_set_complete("add sofia profile ::sofia::list_profiles gwlist ::[up:down");
6380 
6381 	switch_console_set_complete("add sofia recover flush");
6382 
6383 	switch_console_set_complete("add sofia xmlstatus profile ::sofia::list_profiles reg");
6384 	switch_console_set_complete("add sofia xmlstatus gateway ::sofia::list_gateways");
6385 
6386 	switch_console_add_complete_func("::sofia::list_profiles", list_profiles);
6387 	switch_console_add_complete_func("::sofia::list_gateways", list_gateways);
6388 	switch_console_add_complete_func("::sofia::list_profile_gateway", list_profile_gateway);
6389 
6390 
6391 	SWITCH_ADD_API(api_interface, "sofia_username_of", "Sofia Username Lookup", sofia_username_of_function, "[profile/]<user>@<domain>");
6392 	SWITCH_ADD_API(api_interface, "sofia_contact", "Sofia Contacts", sofia_contact_function, "[profile/]<user>@<domain>");
6393 	SWITCH_ADD_API(api_interface, "sofia_count_reg", "Count Sofia registration", sofia_count_reg_function, "[profile/]<user>@<domain>");
6394 	SWITCH_ADD_API(api_interface, "sofia_dig", "SIP DIG", sip_dig_function, "<url>");
6395 	SWITCH_ADD_API(api_interface, "sofia_presence_data", "Sofia Presence Data", sofia_presence_data_function, "[list|status|rpid|user_agent] [profile/]<user>@domain");
6396 	SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send);
6397 
6398 	crtp_init(*module_interface);
6399 
6400 	/* indicate that the module should continue to be loaded */
6401 	return SWITCH_STATUS_SUCCESS;
6402 
6403  err:
6404 
6405 	mod_sofia_shutdown_cleanup();
6406 	return status;
6407 }
6408 
mod_sofia_shutdown_cleanup()6409 void mod_sofia_shutdown_cleanup() {
6410 	int sanity = 0;
6411 	int i;
6412 	switch_status_t st;
6413 
6414 	switch_event_free_subclass(MY_EVENT_NOTIFY_REFER);
6415 	switch_event_free_subclass(MY_EVENT_NOTIFY_WATCHED_HEADER);
6416 	switch_event_free_subclass(MY_EVENT_UNREGISTER);
6417 	switch_event_free_subclass(MY_EVENT_PROFILE_START);
6418 	switch_event_free_subclass(MY_EVENT_REINVITE);
6419 	switch_event_free_subclass(MY_EVENT_REPLACED);
6420 	switch_event_free_subclass(MY_EVENT_TRANSFEROR);
6421 	switch_event_free_subclass(MY_EVENT_TRANSFEREE);
6422 	switch_event_free_subclass(MY_EVENT_ERROR);
6423 	switch_event_free_subclass(MY_EVENT_INTERCEPTED);
6424 	switch_event_free_subclass(MY_EVENT_GATEWAY_STATE);
6425 	switch_event_free_subclass(MY_EVENT_SIP_USER_STATE);
6426 	switch_event_free_subclass(MY_EVENT_GATEWAY_DEL);
6427 	switch_event_free_subclass(MY_EVENT_EXPIRE);
6428 	switch_event_free_subclass(MY_EVENT_REGISTER_ATTEMPT);
6429 	switch_event_free_subclass(MY_EVENT_REGISTER_FAILURE);
6430 	switch_event_free_subclass(MY_EVENT_PRE_REGISTER);
6431 	switch_event_free_subclass(MY_EVENT_REGISTER);
6432 	switch_event_free_subclass(MY_EVENT_GATEWAY_ADD);
6433 	switch_event_free_subclass(MY_EVENT_BYE_RESPONSE);
6434 
6435 	switch_console_del_complete_func("::sofia::list_profiles");
6436 	switch_console_set_complete("del sofia");
6437 
6438 	switch_mutex_lock(mod_sofia_globals.mutex);
6439 	if (mod_sofia_globals.running == 1) {
6440 		mod_sofia_globals.running = 0;
6441 	}
6442 	switch_mutex_unlock(mod_sofia_globals.mutex);
6443 
6444 	switch_event_unbind_callback(sofia_presence_event_handler);
6445 
6446 	switch_event_unbind_callback(general_queue_event_handler);
6447 	switch_event_unbind_callback(event_handler);
6448 
6449 	if (mod_sofia_globals.presence_queue) {
6450 		switch_queue_push(mod_sofia_globals.presence_queue, NULL);
6451 		switch_queue_interrupt_all(mod_sofia_globals.presence_queue);
6452 	}
6453 
6454 	while (mod_sofia_globals.threads) {
6455 		switch_cond_next();
6456 		if (++sanity >= 60000) {
6457 			break;
6458 		}
6459 	}
6460 
6461 	for (i = 0; mod_sofia_globals.msg_queue_thread[i]; i++) {
6462 		switch_queue_push(mod_sofia_globals.msg_queue, NULL);
6463 		switch_queue_interrupt_all(mod_sofia_globals.msg_queue);
6464 	}
6465 
6466 	for (i = 0; mod_sofia_globals.msg_queue_thread[i]; i++) {
6467 		switch_thread_join(&st, mod_sofia_globals.msg_queue_thread[i]);
6468 	}
6469 
6470 	if (mod_sofia_globals.presence_thread) {
6471 		switch_thread_join(&st, mod_sofia_globals.presence_thread);
6472 	}
6473 
6474 	su_deinit();
6475 
6476 	/*
6477 		Release the clone of the default SIP parser
6478 		created by `sip_update_default_mclass(sip_extend_mclass(NULL))` call with NULL argument
6479 	*/
6480 	sip_cloned_parser_destroy();
6481 
6482 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
6483 	switch_core_hash_destroy(&mod_sofia_globals.profile_hash);
6484 	switch_core_hash_destroy(&mod_sofia_globals.gateway_hash);
6485 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
6486 }
6487 
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown)6488 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_sofia_shutdown)
6489 {
6490 	mod_sofia_shutdown_cleanup();
6491 	return SWITCH_STATUS_SUCCESS;
6492 }
6493 
6494 /* For Emacs:
6495  * Local Variables:
6496  * mode:c
6497  * indent-tabs-mode:t
6498  * tab-width:4
6499  * c-basic-offset:4
6500  * End:
6501  * For VIM:
6502  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
6503  */
6504