1 /*!
2  * \file        ast.c
3  * \brief       SCCP PBX Asterisk Wrapper Class
4  * \author      Diederik de Groot <ddegroot [at] users.sourceforge.net>
5  * \note        Reworked, but based on chan_sccp code.
6  *              The original chan_sccp driver that was made by Zozo which itself was derived from the chan_skinny driver.
7  *              Modified by Jan Czmok and Julien Goodwin
8  * \note        This program is free software and may be modified and distributed under the terms of the GNU Public License.
9  *              See the LICENSE file at the top of the source tree.
10  */
11 #include "config.h"
12 #include "common.h"
13 #include "sccp_channel.h"
14 #include "sccp_device.h"
15 #include "sccp_indicate.h"
16 #include "sccp_netsock.h"
17 #include "sccp_session.h"
18 #include "sccp_utils.h"
19 #include "sccp_pbx.h"
20 #include "sccp_atomic.h"
21 #include "sccp_line.h"
22 #include "sccp_linedevice.h"
23 
24 SCCP_FILE_VERSION(__FILE__, "");
25 
26 #include <asterisk.h>
27 #ifdef HAVE_PBX_ACL_H				// ast_str2cos ast_str2tos
28 #  include <asterisk/acl.h>
29 #endif
30 #include <asterisk/causes.h>
31 #ifdef HAVE_PBX_APP_H
32 #  include <asterisk/app.h>
33 #endif
34 #include <asterisk/callerid.h>
35 #include <asterisk/astdb.h>
36 #include <asterisk/musiconhold.h>
37 #ifdef HAVE_PBX_FEATURES_H
38 #  include <asterisk/features.h>
39 #endif
40 #if ASTERISK_VERSION_GROUP >= 112
41 #include <asterisk/features_config.h>
42 #include <asterisk/pickup.h>
43 #endif
44 
45 /*!
46  * \brief Skinny Codec Mapping
47  */
48 static const struct pbx2skinny_codec_map {
49        pbx_format_enum_type pbx_codec;
50        skinny_codec_t skinny_codec;
51 } pbx2skinny_codec_maps[] = {
52        /* *INDENT-OFF* */
53        {(pbx_format_enum_type)0,SKINNY_CODEC_NONE},
54        {AST_FORMAT_ALAW,       SKINNY_CODEC_G711_ALAW_64K},
55        {AST_FORMAT_ALAW,       SKINNY_CODEC_G711_ALAW_56K},
56        {AST_FORMAT_ULAW,       SKINNY_CODEC_G711_ULAW_64K},
57        {AST_FORMAT_ULAW,       SKINNY_CODEC_G711_ULAW_56K},
58        {AST_FORMAT_GSM,        SKINNY_CODEC_GSM},
59        {AST_FORMAT_H261,       SKINNY_CODEC_H261},
60        {AST_FORMAT_H263,       SKINNY_CODEC_H263},
61        {AST_FORMAT_T140,       SKINNY_CODEC_T120},
62 #    if ASTERISK_VERSION_GROUP >= 113
63        {AST_FORMAT_G723,       SKINNY_CODEC_G723_1},
64        {AST_FORMAT_SLIN16,     SKINNY_CODEC_WIDEBAND_256K},
65        {AST_FORMAT_G729,       SKINNY_CODEC_G729},
66        {AST_FORMAT_G729,       SKINNY_CODEC_G729_A},
67        {AST_FORMAT_H263P,      SKINNY_CODEC_H263P},
68 #    else
69        {AST_FORMAT_G723_1,     SKINNY_CODEC_G723_1},
70        {AST_FORMAT_SLINEAR16,  SKINNY_CODEC_WIDEBAND_256K},
71        {AST_FORMAT_G729A,      SKINNY_CODEC_G729},
72        {AST_FORMAT_G729A,      SKINNY_CODEC_G729_A},
73        {AST_FORMAT_H263_PLUS,  SKINNY_CODEC_H263P},
74 #    endif
75 #    if ASTERISK_VERSION_NUMBER >= 10400
76        {AST_FORMAT_G726_AAL2,  SKINNY_CODEC_G726_32K},
77        {AST_FORMAT_G726,       SKINNY_CODEC_G726_32K},
78        {AST_FORMAT_ILBC,       SKINNY_CODEC_G729_B_LOW},
79        {AST_FORMAT_G722,       SKINNY_CODEC_G722_64K},
80        {AST_FORMAT_G722,       SKINNY_CODEC_G722_56K},
81        {AST_FORMAT_G722,       SKINNY_CODEC_G722_48K},
82        {AST_FORMAT_H264,       SKINNY_CODEC_H264},
83 #    endif
84 #    ifdef AST_FORMAT_SIREN7
85        {AST_FORMAT_SIREN7,     SKINNY_CODEC_G722_1_24K},                       // should this not be SKINNY_CODEC_G722_1_32K
86 #    endif
87 #    ifdef AST_FORMAT_SIREN14
88        {AST_FORMAT_SIREN14,    SKINNY_CODEC_G722_1_32K},                       // should this not be SKINNY_CODEC_G722_1_48K
89 #    endif
90 #    ifdef AST_FORMAT_OPUS
91        {AST_FORMAT_OPUS,       SKINNY_CODEC_OPUS},
92 #    endif
93        /* *INDENT-ON* */
94 };
95 
96 /*!
97  * \brief AST Device State Structure
98  */
99 static const struct sccp_pbx_devicestate {
100 	const char *const text;
101 #ifdef ENUM_AST_DEVICE
102 	enum ast_device_state devicestate;
103 #else
104 	uint8_t devicestate;
105 #endif
106 } sccp_pbx_devicestates[] = {
107 	/* *INDENT-OFF* */
108 	{"Device is valid but channel doesn't know state",	AST_DEVICE_UNKNOWN},
109 	{"Device is not in use",				AST_DEVICE_NOT_INUSE},
110 	{"Device is in use",					AST_DEVICE_INUSE},
111 	{"Device is busy",					AST_DEVICE_BUSY},
112 	{"Device is invalid",					AST_DEVICE_INVALID},
113 	{"Device is unavailable",				AST_DEVICE_UNAVAILABLE},
114 	{"Device is ringing",					AST_DEVICE_RINGING},
115 	{"Device is ringing and in use",			AST_DEVICE_RINGINUSE},
116 	{"Device is on hold",					AST_DEVICE_ONHOLD},
117 #    ifdef AST_DEVICE_TOTAL
118 	{"Total num of device states, used for testing",	AST_DEVICE_TOTAL},
119 #    endif
120 	/* *INDENT-ON* */
121 };
122 
pbxsccp_devicestate2str(uint32_t value)123 gcc_inline const char *pbxsccp_devicestate2str(uint32_t value)
124 {														/* pbx_impl/ast/ast.h */
125 	_ARR2STR(sccp_pbx_devicestates, devicestate, value, text);
126 }
127 
128 #if UNUSEDCODE // 2015-11-01
129 /*!
130  * \brief SCCP Extension State Structure
131  */
132 static const struct sccp_extension_state {
133 	const char *const text;
134 	int extension_state;
135 } sccp_extension_states[] = {
136 	/* *INDENT-OFF* */
137 	{"Extension Removed",					AST_EXTENSION_REMOVED},
138 	{"Extension Hint Removed",				AST_EXTENSION_DEACTIVATED},
139 	{"No device INUSE or BUSY",				AST_EXTENSION_NOT_INUSE},
140 	{"One or More devices In Use",				AST_EXTENSION_INUSE},
141 	{"All devices Busy",					AST_EXTENSION_BUSY},
142 	{"All devices Unavailable/Unregistered",		AST_EXTENSION_UNAVAILABLE},
143 #    ifdef CS_AST_HAS_EXTENSION_RINGING
144 	{"All Devices Ringing",					AST_EXTENSION_RINGING},
145 	{"All Devices Ringing and In Use",			AST_EXTENSION_INUSE | AST_EXTENSION_RINGING},
146 #    endif
147 #    ifdef CS_AST_HAS_EXTENSION_ONHOLD
148 	{"All Devices On Hold",					AST_EXTENSION_ONHOLD},
149 #    endif
150 	/* *INDENT-ON* */
151 };
152 
extensionstatus2str(uint32_t value)153 gcc_inline const char *extensionstatus2str(uint32_t value)
154 {														/* pbx_impl/ast/ast.h */
155 	_ARR2STR(sccp_extension_states, extension_state, value, text);
156 }
157 #endif
158 
159 #if UNUSEDCODE // 2015-11-01
160 /*!
161  * \brief Ast Cause - Skinny DISP Mapping
162  */
163 static const struct pbx_skinny_cause {
164 	const char *skinny_disp;
165 	const char *message;
166 	int pbx_cause;
167 } pbx_skinny_causes[] = {
168 	/* *INDENT-OFF* */
169         { AST_CAUSE_UNALLOCATED,		, "Unallocated (unassigned) number", 		SKINNY_DISP_NUMBER_NOT_CONFIGURED},
170         { AST_CAUSE_NO_ROUTE_TRANSIT_NET,	, "No route to specified transmit network", 	SKINNY_DISP_UNKNOWN_NUMBER},
171         { AST_CAUSE_NO_ROUTE_DESTINATION,	, "No route to destination", 			SKINNY_DISP_UNKNOWN_NUMBER},
172         { AST_CAUSE_CHANNEL_UNACCEPTABLE,	, "Channel unacceptable", 			SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
173 #if ASTERISK_VERSION_GROUP >= 108
174 	{ AST_CAUSE_MISDIALLED_TRUNK_PREFIX,   	, "Misdialled Trunk Prefix", 			SKINNY_DISP_UNKNOWN_NUMBER},
175 #endif
176         { AST_CAUSE_CALL_AWARDED_DELIVERED,	, "Call awarded and being delivered in an established channel", SKINNY_DISP_CONNECTED},
177         { AST_CAUSE_NORMAL_CLEARING,		, "Normal Clearing",				SKINNY_DISP_ON_HOOK},
178 	{ AST_CAUSE_PRE_EMPTED,			, "Pre Empted", 				SKINNY_DISP_HIGH_TRAFFIC_TRY_AGAIN_LATER},
179         { AST_CAUSE_USER_BUSY, 			, "User busy", 					SKINNY_DISP_BUSY},
180 #if ASTERISK_VERSION_GROUP >= 108
181 	{ AST_CAUSE_NUMBER_PORTED_NOT_HERE,	, "Number not configured", 			SKINNY_DISP_NUMBER_NOT_CONFIGURED},
182 #endif
183 	{ AST_CAUSE_SUBSCRIBER_ABSENT,		, "Subscriber Absent, Try Again", 		SKINNY_DISP_TEMP_FAIL},
184 	{ AST_CAUSE_ANSWERED_ELSEWHERE,		, "Answered Elsewhere", 			SKINNY_DISP_CONNECTED},
185 	{ AST_CAUSE_NO_USER_RESPONSE,		, "No user responding", 			SKINNY_DISP_EMPTY},
186         { AST_CAUSE_NO_ANSWER,			, "User alerting, no answer", 			SKINNY_DISP_EMPTY},
187         { AST_CAUSE_CALL_REJECTED,		, "Call Rejected", 				SKINNY_DISP_BUSY},
188 	{ AST_CAUSE_NUMBER_CHANGED,		, "Number changed", 				SKINNY_DISP_NUMBER_NOT_CONFIGURED},
189         { AST_CAUSE_DESTINATION_OUT_OF_ORDER,	, "Destination out of order", 			SKINNY_DISP_TEMP_FAIL},
190         { AST_CAUSE_INVALID_NUMBER_FORMAT, 	, "Invalid number format", 			SKINNY_DISP_UNKNOWN_NUMBER },
191         { AST_CAUSE_FACILITY_REJECTED,		, "Facility rejected", 				SKINNY_DISP_TEMP_FAIL},
192 	{ AST_CAUSE_RESPONSE_TO_STATUS_ENQUIRY,	, "Response to STATus ENQuiry", 		SKINNY_DISP_TEMP_FAIL},
193         { AST_CAUSE_NORMAL_UNSPECIFIED,		, "Normal, unspecified", 			SKINNY_DISP_TEMP_FAIL},
194   	{ AST_CAUSE_NORMAL_CIRCUIT_CONGESTION,	, "Circuit/channel congestion", 		SKINNY_DISP_HIGH_TRAFFIC_TRY_AGAIN_LATER},
195         { AST_CAUSE_NETWORK_OUT_OF_ORDER, 	, "Network out of order", 			SKINNY_DISP_NETWORK_CONGESTION_REROUTING},
196   	{ AST_CAUSE_NORMAL_TEMPORARY_FAILURE, 	, "Temporary failure", 				SKINNY_DISP_TEMP_FAIL},
197         { AST_CAUSE_SWITCH_CONGESTION,		, "Switching equipment congestion",	 	SKINNY_DISP_HIGH_TRAFFIC_TRY_AGAIN_LATER},
198 	{ AST_CAUSE_ACCESS_INFO_DISCARDED,	, "Access information discarded", 		SKINNY_DISP_SECURITY_ERROR},
199         { AST_CAUSE_REQUESTED_CHAN_UNAVAIL,	, "Requested channel not available", 		SKINNY_DISP_HIGH_TRAFFIC_TRY_AGAIN_LATER},
200 	{ AST_CAUSE_PRE_EMPTED,			, "Pre-empted", 				SKINNY_DISP_HIGH_TRAFFIC_TRY_AGAIN_LATER},
201         { AST_CAUSE_FACILITY_NOT_SUBSCRIBED,	, "Facility not subscribed", 			SKINNY_DISP_TEMP_FAIL},
202 	{ AST_CAUSE_OUTGOING_CALL_BARRED,	, "Outgoing call barred", 			SKINNY_DISP_SECURITY_ERROR},
203         { AST_CAUSE_INCOMING_CALL_BARRED,	, "Incoming call barred", 			SKINNY_DISP_SECURITY_ERROR},
204 	{ AST_CAUSE_BEARERCAPABILITY_NOTAUTH,	, "Bearer capability not authorized", 		SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
205         { AST_CAUSE_BEARERCAPABILITY_NOTAVAIL,	, "Bearer capability not available", 		SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
206         { AST_CAUSE_BEARERCAPABILITY_NOTIMPL,	, "Bearer capability not implemented", 		SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
207         { AST_CAUSE_CHAN_NOT_IMPLEMENTED,	, "Channel not implemented", 			SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
208 	{ AST_CAUSE_FACILITY_NOT_IMPLEMENTED,	, "Facility not implemented", 			SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
209         { AST_CAUSE_INVALID_CALL_REFERENCE,	, "Invalid call reference value", 		SKINNY_DISP_TEMP_FAIL},
210 	{ AST_CAUSE_INCOMPATIBLE_DESTINATION,	, "Incompatible destination", 			SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
211         { AST_CAUSE_INVALID_MSG_UNSPECIFIED,	, "Invalid message unspecified", 		SKINNY_DISP_ERROR_UNKNOWN},
212         { AST_CAUSE_MANDATORY_IE_MISSING,	, "Mandatory information element is missing", 	SKINNY_DISP_CAN_NOT_HOLD_PRIMARY_CONTROL},
213         { AST_CAUSE_MESSAGE_TYPE_NONEXIST,	, "Message type nonexist.", 			SKINNY_DISP_CAN_NOT_HOLD_PRIMARY_CONTROL},
214   	{ AST_CAUSE_WRONG_MESSAGE,		, "Wrong message", 				SKINNY_DISP_ERROR_MISMATCH},
215         { AST_CAUSE_IE_NONEXIST,		, "Info. element nonexist or not implemented", 	SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
216 	{ AST_CAUSE_INVALID_IE_CONTENTS,	, "Invalid information element contents", 	SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
217         { AST_CAUSE_WRONG_CALL_STATE,		, "Message not compatible with call state", 	SKINNY_DISP_TEMP_FAIL},
218 	{ AST_CAUSE_RECOVERY_ON_TIMER_EXPIRE,	, "Recover on timer expiry", 			SKINNY_DISP_MAX_CALL_DURATION_TIMEOUT},
219         { AST_CAUSE_MANDATORY_IE_LENGTH_ERROR,	, "Mandatory IE length error", 			SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
220 	{ AST_CAUSE_PROTOCOL_ERROR,		, "Protocol error, unspecified", 		SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
221         { AST_CAUSE_INTERWORKING,		, "Interworking, unspecified", 			SKINNY_DISP_NETWORK_CONGESTION_REROUTING},
222 
223         // aliases for backward compatibility reasons
224 	{ AST_CAUSE_BUSY,			, "User busy", 					SKINNY_DISP_BUSY},
225 	{ AST_CAUSE_FAILURE,			, "Network out of order", 			SKINNY_DISP_NETWORK_CONGESTION_REROUTING},
226 	{ AST_CAUSE_NORMAL,			, "Normal Clearing", 				SKINNY_DISP_ON_HOOK},
227 	{ AST_CAUSE_NOANSWER,			, "User alerting, no answer", 			SKINNY_DISP_EMPTY},
228 	{ AST_CAUSE_CONGESTION,    		, "Circuit/channel congestion", 		SKINNY_DISP_HIGH_TRAFFIC_TRY_AGAIN_LATER},
229 	{ AST_CAUSE_UNREGISTERED,  		, "Subscriber Absent, Try Again", 		SKINNY_DISP_TEMP_FAIL},
230 	{ AST_CAUSE_NOTDEFINED,    		, "Not Defined", 				SKINNY_DISP_EMPTY},
231 	{ AST_CAUSE_NOSUCHDRIVER,		, "Channel not implemented", 			SKINNY_DISP_INCOMPATIBLE_DEVICE_TYPE},
232 	/* *INDENT-ON* */
233 };
234 #endif
235 
236 /*
237  * \brief itterate through locked pbx channels
238  * \note replacement for ast_channel_walk_locked
239  * \param ast_chan Asterisk Channel
240  * \return ast_chan Locked Asterisk Channel
241  *
242  * \todo implement pbx_channel_walk_locked or replace
243  * \deprecated
244  */
245 #if UNUSEDCODE // 2015-11-01
pbx_channel_walk_locked(PBX_CHANNEL_TYPE * target)246 PBX_CHANNEL_TYPE *pbx_channel_walk_locked(PBX_CHANNEL_TYPE * target)
247 {
248 #if ASTERISK_VERSION_NUMBER >= 10800
249 	struct ast_channel_iterator *iter = ast_channel_iterator_all_new();
250 	PBX_CHANNEL_TYPE *res = NULL;
251 	PBX_CHANNEL_TYPE *tmp = NULL;
252 
253 	/* no target given, so just start iteration */
254 	if (!target) {
255 		tmp = ast_channel_iterator_next(iter);
256 	} else {
257 		/* search for our target channel and use the next iteration value */
258 		while ((tmp = ast_channel_iterator_next(iter)) != NULL) {
259 			if (tmp == target) {
260 				tmp = ast_channel_iterator_next(iter);
261 				break;
262 			}
263 		}
264 	}
265 
266 	if (tmp) {
267 		res = tmp;
268 		tmp = pbx_channel_unref(tmp);
269 		ast_channel_lock(res);
270 	}
271 	ast_channel_iterator_destroy(iter);
272 	return res;
273 #else
274 	return ast_channel_walk_locked(target);
275 #endif
276 }
277 #endif
278 
279 /************************************************************************************************************** CONFIG **/
280 
281 /*
282  * \brief Add a new rule to a list of HAs
283  * \note replacement for ast_append_ha
284  * \param sense Sense / Key
285  * \param stuff Value / Stuff to Add
286  * \param path list of HAs
287  * \param error Error as int
288  * \return The head of the HA list
289  *
290  * \deprecated
291  */
292 #if UNUSEDCODE // 2015-11-01
pbx_append_ha(NEWCONST char * sense,const char * stuff,struct ast_ha * path,int * error)293 pbx_channel_walk_lockedstruct ast_ha *pbx_append_ha(NEWCONST char *sense, const char *stuff, struct ast_ha *path, int *error)
294 {
295 #if ASTERISK_VERSION_NUMBER < 10600
296 	return ast_append_ha(sense, stuff, path);
297 #else
298 	return ast_append_ha(sense, stuff, path, error);
299 #endif														// ASTERISK_VERSION_NUMBER
300 }
301 #endif
302 
303 /*
304  * \brief Register a new context
305  * \note replacement for ast_context_find_or_create
306  *
307  * This will first search for a context with your name.  If it exists already, it will not
308  * create a new one.  If it does not exist, it will create a new one with the given name
309  * and registrar.
310  *
311  * \param extcontexts pointer to the ast_context structure pointer
312  * \param name name of the new context
313  * \param registrar registrar of the context
314  * \return NULL on failure, and an ast_context structure on success
315  */
pbx_context_find_or_create(struct ast_context ** extcontexts,struct ast_hashtab * exttable,const char * name,const char * registrar)316 struct ast_context *pbx_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
317 {
318 #if ASTERISK_VERSION_NUMBER < 10600
319 	return ast_context_find_or_create(extcontexts, name, registrar);
320 #else
321 	return ast_context_find_or_create(extcontexts, exttable, name, registrar);
322 #endif														// ASTERISK_VERSION_NUMBER
323 }
324 
325 /*!
326  * \brief Load a config file
327  *
328  * \param filename path of file to open.  If no preceding '/' character,
329  * path is considered relative to AST_CONFIG_DIR
330  * \param who_asked The module which is making this request.
331  * \param flags Optional flags:
332  * CONFIG_FLAG_WITHCOMMENTS - load the file with comments intact;
333  * CONFIG_FLAG_FILEUNCHANGED - check the file mtime and return CONFIG_STATUS_FILEUNCHANGED if the mtime is the same; or
334  * CONFIG_FLAG_NOCACHE - don't cache file mtime (main purpose of this option is to save memory on temporary files).
335  *
336  * \details
337  * Create a config structure from a given configuration file.
338  *
339  * \return an ast_config data structure on success
340  * \retval NULL on error
341  */
pbx_config_load(const char * filename,const char * who_asked,struct ast_flags flags)342 struct ast_config *pbx_config_load(const char *filename, const char *who_asked, struct ast_flags flags)
343 {
344 #if ASTERISK_VERSION_NUMBER < 10600
345 	return ast_config_load(filename);
346 #else
347 	return ast_config_load2(filename, who_asked, flags);
348 #endif														// ASTERISK_VERSION_NUMBER
349 }
350 
351 /******************************************************************************************************** NET / SOCKET **/
352 
353 /*
354  * \brief thread-safe replacement for inet_ntoa()
355  * \note replacement for ast_pbx_inet_ntoa
356  * \param ia In Address / Source Address
357  * \return Address as char
358  */
pbx_inet_ntoa(struct in_addr ia)359 const char *pbx_inet_ntoa(struct in_addr ia)
360 {
361 #if ASTERISK_VERSION_NUMBER < 10400
362 	char iabuf[INET_ADDRSTRLEN];
363 
364 	return ast_inet_ntoa(iabuf, sizeof(iabuf), ia);
365 #else
366 	return ast_inet_ntoa(ia);
367 #endif														// ASTERISK_VERSION_NUMBER
368 }
369 
370 #if ASTERISK_VERSION_NUMBER < 10400
371 
372 /* BackPort of ast_str2cos & ast_str2cos for asterisk 1.2 */
373 struct dscp_codepoint {
374 	char *name;
375 	unsigned int space;
376 };
377 
378 static const struct dscp_codepoint dscp_pool1[] = {
379 	{"CS0", 0x00},
380 	{"CS1", 0x08},
381 	{"CS2", 0x10},
382 	{"CS3", 0x18},
383 	{"CS4", 0x20},
384 	{"CS5", 0x28},
385 	{"CS6", 0x30},
386 	{"CS7", 0x38},
387 	{"AF11", 0x0A},
388 	{"AF12", 0x0C},
389 	{"AF13", 0x0E},
390 	{"AF21", 0x12},
391 	{"AF22", 0x14},
392 	{"AF23", 0x16},
393 	{"AF31", 0x1A},
394 	{"AF32", 0x1C},
395 	{"AF33", 0x1E},
396 	{"AF41", 0x22},
397 	{"AF42", 0x24},
398 	{"AF43", 0x26},
399 	{"EF", 0x2E},
400 };
401 
pbx_str2tos(const char * value,uint8_t * tos)402 int pbx_str2tos(const char *value, uint8_t *tos)
403 {
404 	int fval;
405 
406 	unsigned int x;
407 
408 	if (sscanf(value, "%30i", &fval) == 1) {
409 		*tos = (uint16_t)fval & 0xFF;
410 		return *tos;
411 	}
412 
413 	for (x = 0; x < ARRAY_LEN(dscp_pool1); x++) {
414 		if (!strcasecmp(value, dscp_pool1[x].name)) {
415 			*tos = (uint8_t)dscp_pool1[x].space << 2;
416 			return *tos;
417 		}
418 	}
419 
420 	return 0;
421 }
422 #else
pbx_str2tos(const char * value,uint8_t * tos)423 int pbx_str2tos(const char *value, uint8_t *tos)
424 {
425 	uint32_t tos_value = 0;
426 	ast_str2tos(value, &tos_value);
427 	*tos = (uint8_t) tos_value;
428 	return *tos;
429 }
430 #endif														// ASTERISK_VERSION_NUMBER
431 
432 #if ASTERISK_VERSION_NUMBER < 10600
pbx_str2cos(const char * value,uint8_t * cos)433 int pbx_str2cos(const char *value, uint8_t *cos)
434 {
435 	int fval;
436 
437 	if (sscanf(value, "%30d", &fval) == 1) {
438 		if (fval < 8) {
439 			*cos = (uint8_t)fval;
440 			return *cos;
441 		}
442 	}
443 
444 	return 0;
445 }
446 #else
pbx_str2cos(const char * value,uint8_t * cos)447 int pbx_str2cos(const char *value, uint8_t *cos)
448 {
449 	uint32_t cos_value = 0;
450 	ast_str2cos(value, &cos_value);
451 	*cos = (uint8_t) cos_value;
452 	return *cos;
453 }
454 #endif														// ASTERISK_VERSION_NUMBER
455 
456 /************************************************************************************************************* GENERAL **/
457 
458 #if UNUSEDCODE // 2015-11-01
459 /*!
460  * \brief Simply remove extension from context
461  * \note replacement for ast_context_remove_extension
462  *
463  * \param context context to remove extension from
464  * \param extension which extension to remove
465  * \param priority priority of extension to remove (0 to remove all)
466  * \param registrar registrar of the extension
467  *
468  * This function removes an extension from a given context.
469  *
470  * \retval 0 on success
471  * \retval -1 on failure
472  *
473  * @{
474  */
pbx_context_remove_extension(const char * context,const char * extension,int priority,const char * registrar)475 int pbx_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
476 {
477 #if ASTERISK_VERSION_NUMBER >= 10600
478 	struct pbx_find_info q = {.stacklen = 0 };
479 	if (pbx_find_extension(NULL, NULL, &q, context, extension, 1, NULL, "", E_MATCH)) {
480 		return ast_context_remove_extension(context, extension, priority, registrar);
481 	} else {
482 		return -1;
483 	}
484 #else
485 	return ast_context_remove_extension(context, extension, priority, registrar);
486 #endif														// ASTERISK_VERSION_NUMBER
487 }
488 #endif
489 
490 /*!
491  * \brief Send ack in manager list transaction
492  * \note replacement for astman_send_listack
493  * \param s Management Session
494  * \param m Management Message
495  * \param msg Message
496  * \param listflag List Flag
497  */
pbxman_send_listack(struct mansession * s,const struct message * m,char * msg,char * listflag)498 void pbxman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
499 {
500 #if ASTERISK_VERSION_NUMBER < 10600
501 	astman_send_ack(s, m, msg);
502 #else
503 	astman_send_listack(s, m, msg, listflag);
504 #endif														// ASTERISK_VERSION_NUMBER
505 }
506 
507 /****************************************************************************************************** CODEC / FORMAT **/
508 
509 /*!
510  * \brief Convert a ast_codec (fmt) to a skinny codec (enum)
511  *
512  * \param fmt Format as ast_format_type
513  *
514  * \return skinny_codec
515  */
pbx_codec2skinny_codec(ast_format_type fmt)516 skinny_codec_t __CONST__ pbx_codec2skinny_codec(ast_format_type fmt)
517 {
518 	uint32_t i;
519 
520 	for (i = 1; i < ARRAY_LEN(pbx2skinny_codec_maps); i++) {
521 		if (pbx2skinny_codec_maps[i].pbx_codec == (uint64_t) fmt) {
522 			return pbx2skinny_codec_maps[i].skinny_codec;
523 		}
524 	}
525 	return SKINNY_CODEC_NONE;
526 }
527 
528 /*!
529  * \brief Convert a skinny_codec (enum) to an ast_codec (fmt)
530  *
531  * \param codec Skinny Codec (enum)
532  *
533  * \return fmt Format as ast_format_type
534  */
skinny_codec2pbx_codec(skinny_codec_t codec)535 pbx_format_enum_type __CONST__ skinny_codec2pbx_codec(skinny_codec_t codec)
536 {
537 	uint32_t i;
538 
539 	for (i = 1; i < ARRAY_LEN(pbx2skinny_codec_maps); i++) {
540 		if (pbx2skinny_codec_maps[i].skinny_codec == codec) {
541 			return pbx2skinny_codec_maps[i].pbx_codec;
542 		}
543 	}
544 	return (pbx_format_enum_type)0;
545 }
546 
547 /*!
548  * \brief Convert an array of skinny_codecs (enum) to a bit array of ast_codecs (fmt)
549  *
550  * \param codecs Array of Skinny Codecs
551  *
552  * \return bit array fmt/Format of ast_format_type (int)
553  */
skinny_codecs2pbx_codecs(const skinny_codec_t * const codecs)554 pbx_format_type __PURE__ skinny_codecs2pbx_codecs(const skinny_codec_t * const codecs)
555 {
556 	uint32_t i;
557 	int res_codec = 0;
558 
559 	for (i = 1; i < SKINNY_MAX_CAPABILITIES; i++) {
560 		res_codec |= skinny_codec2pbx_codec(codecs[i]);
561 	}
562 	return res_codec;
563 }
564 
565 /*!
566  * \brief Retrieve the SCCP Channel from an Asterisk Channel
567  *
568  * \param pbx_channel PBX Channel
569  * \return SCCP Channel on Success or Null on Fail
570  *
571  * \todo this code is not pbx independent
572  */
get_sccp_channel_from_pbx_channel(const PBX_CHANNEL_TYPE * pbx_channel)573 sccp_channel_t *get_sccp_channel_from_pbx_channel(const PBX_CHANNEL_TYPE * pbx_channel)
574 {
575 	sccp_channel_t *c = NULL;
576 
577 	if (pbx_channel && CS_AST_CHANNEL_PVT(pbx_channel) && CS_AST_CHANNEL_PVT_CMP_TYPE(pbx_channel, "SCCP")) {
578 		if ((c = CS_AST_CHANNEL_PVT(pbx_channel))) {
579 			return sccp_channel_retain(c);
580 		}
581 		pbx_log(LOG_ERROR, "Channel is not a valid SCCP Channel\n");
582 		return NULL;
583 	} else {
584 		return NULL;
585 	}
586 }
587 
588 /*
589 static void log_hangup_info(const char * hanguptype, constChannelPtr c, PBX_CHANNEL_TYPE * const pbx_channel)
590 {
591 	sccp_log(DEBUGCAT_PBX)("%s: (%s):\n"
592 			       " - pbx_channel: %s\n"
593 			       " - channel_flags:\n"
594 			       "   - ZOMBIE: %s\n"
595 			       "   - BLOCKING: %s\n"
596 			       " - pbx_channel_hangup_locked: %s\n"
597 			       " - runningPbxThread: %s\n"
598 			       " - pbx_channel_is_bridged: %s\n"
599 			       " - pbx_channel_pbx: %s\n",
600 			       c->designator, hanguptype, pbx_channel ? pbx_channel_name(pbx_channel) : "", pbx_channel ? pbx_test_flag(pbx_channel_flags(pbx_channel), AST_FLAG_ZOMBIE) ? "YES" : "NO" : "",
601 			       pbx_channel ? pbx_test_flag(pbx_channel_flags(pbx_channel), AST_FLAG_BLOCKING) ? "YES" : "NO" : "", pbx_channel ? pbx_check_hangup_locked(pbx_channel) ? "YES" : "NO" : "",
602 			       c->isRunningPbxThread ? "YES" : "NO", iPbx.channel_is_bridged((channelPtr)c) ? "YES" : "NO", pbx_channel ? pbx_channel_pbx(pbx_channel) ? "YES" : "NO" : "");
603 #if CS_REFCOUNT_DEBUG
604 	AUTO_RELEASE(sccp_device_t, d, sccp_channel_getDevice(c));
605 	if(d) {
606 		pbx_str_t * buf = pbx_str_create(DEFAULT_PBX_STR_BUFFERSIZE * 3);
607 		sccp_refcount_gen_report(d, &buf);
608 		pbx_log(LOG_NOTICE, "%s: (%s) refcount_report:\n%s\n", c->designator, hanguptype, pbx_str_buffer(buf));
609 		sccp_free(buf);
610 	}
611 #endif
612 }
613 */
sccp_astgenwrap_handleHangup(constChannelPtr channel,const char * hanguptype)614 static boolean_t sccp_astgenwrap_handleHangup(constChannelPtr channel, const char * hanguptype)
615 {
616 	boolean_t res = FALSE;
617 	int tries = 10;
618 	AUTO_RELEASE(sccp_channel_t, c, sccp_channel_retain(channel));
619 	if (channel) {
620 		c->isHangingUp = TRUE;
621 		PBX_CHANNEL_TYPE * pbx_channel = pbx_channel_ref(c->owner);
622 
623 		if(ATOMIC_FETCH(&c->scheduler.deny, &c->scheduler.lock) == 0) {
624 			sccp_channel_stop_and_deny_scheduled_tasks(c);
625 		}
626 		do {
627 			// log_hangup_info(hanguptype, c, pbx_channel);
628 			if(!pbx_channel || pbx_test_flag(pbx_channel_flags(pbx_channel), AST_FLAG_ZOMBIE) || pbx_check_hangup_locked(pbx_channel)) {
629 				AUTO_RELEASE(sccp_device_t, d, sccp_channel_getDevice(c));
630 				if(d) {
631 					sccp_indicate(d, c, SCCP_CHANNELSTATE_ONHOOK);
632 					sccp_log(DEBUGCAT_PBX)("%s: (%s): Onhook Only\n", c->designator, hanguptype);
633 				}
634 				if(iPbx.dumpchan) {
635 					char * buf = sccp_alloca(sizeof(char) * 2048);
636 					iPbx.dumpchan(pbx_channel, buf, 2048);
637 					sccp_log(DEBUGCAT_PBX)("SCCP: (dumpchan) %s", buf);
638 				}
639 				res = TRUE;
640 				break;
641 			}
642 			pbx_channel_lock(pbx_channel);
643 			if(pbx_check_hangup(pbx_channel)) {
644 				// already being hungup
645 				sccp_log(DEBUGCAT_PBX)("%s: (%s): Already being hungup, giving up\n", c->designator, hanguptype);
646 				res = FALSE;
647 				break;
648 			}
649 			if(c->isRunningPbxThread || pbx_channel_pbx(pbx_channel)) {
650 				// outbound / call initiator (running pbx_pbx_start)
651 				sccp_log(DEBUGCAT_PBX)("%s: (%s): Hangup Queued\n", c->designator, hanguptype);
652 				pbx_channel_unlock(pbx_channel);
653 				res = ast_queue_hangup(pbx_channel) ? FALSE : TRUE;
654 				res = TRUE;
655 				break;
656 			}
657 			if(SCCP_CHANNELSTATE_IsSettingUp(c->state) || SCCP_CHANNELSTATE_IsConnected(c->state) || iPbx.channel_is_bridged(c)) {
658 				// inbound / receiving call
659 				sccp_log(DEBUGCAT_PBX)("%s: (%s): Softhangup\n", c->designator, hanguptype);
660 				ast_softhangup(pbx_channel, AST_SOFTHANGUP_DEV);
661 				pbx_channel_unlock(pbx_channel);
662 				res = TRUE;
663 				break;
664 			}
665 			if(pbx_test_flag(pbx_channel_flags(pbx_channel), AST_FLAG_BLOCKING)) { /* not sure if required */
666 				// blocking while being the initiator of the call, strange
667 				sccp_log(DEBUGCAT_PBX)("%s: (%s): Blocker detected, SIGURG signal sent\n", c->designator, hanguptype);
668 				pthread_kill(pbx_channel_blocker(pbx_channel), SIGURG);
669 				sched_yield();
670 				pbx_safe_sleep(pbx_channel, 1000);
671 				pbx_channel_unlock(pbx_channel);
672 				res = TRUE;
673 				break;
674 			}
675 			if(SCCP_CHANNELSTATE_Idling(c->state) || SCCP_CHANNELSTATE_IsDialing(c->state) || SCCP_CHANNELSTATE_IsTerminating(c->state)) {
676 				/* hard hangup for all partially started calls */
677 				sccp_log(DEBUGCAT_PBX)("%s: (%s): Hard Hangup\n", c->designator, hanguptype);
678 				pbx_channel_unlock(pbx_channel);
679 				ast_hangup(pbx_channel);
680 				res = TRUE;
681 				break;
682 			}
683 		} while(tries--);
684 		pbx_channel_unref(pbx_channel);
685 	}
686 	return res;
687 }
688 
sccp_astgenwrap_carefullHangup(constChannelPtr c)689 static boolean_t sccp_astgenwrap_carefullHangup(constChannelPtr c)
690 {
691 	boolean_t res = FALSE;
692 	AUTO_RELEASE(sccp_channel_t, channel , sccp_channel_retain(c));
693 	if (channel) {
694 		channel->isHangingUp = TRUE;
695 		PBX_CHANNEL_TYPE *pbx_channel = pbx_channel_ref(channel->owner);
696 		sched_yield();
697 		pbx_safe_sleep(pbx_channel, 1000);
698 		res = sccp_astgenwrap_handleHangup(channel, "RequestCarefullHangup");
699 		pbx_channel_unref(pbx_channel);
700 	}
701 	return res;
702 }
703 
sccp_astgenwrap_requestQueueHangup(constChannelPtr c)704 boolean_t sccp_astgenwrap_requestQueueHangup(constChannelPtr c)
705 {
706 	return sccp_astgenwrap_handleHangup(c, "RequestQueueHangup");
707 }
708 
sccp_astgenwrap_requestHangup(constChannelPtr c)709 boolean_t sccp_astgenwrap_requestHangup(constChannelPtr c)
710 {
711 	return sccp_astgenwrap_handleHangup(c, "RequestHangup");
712 }
713 
714 /***** database *****/
sccp_astwrap_addToDatabase(const char * family,const char * key,const char * value)715 boolean_t sccp_astwrap_addToDatabase(const char *family, const char *key, const char *value)
716 {
717 	int res;
718 
719 	// pbx_log(LOG_NOTICE, "family:%s, key:%s, value:%s\n", family, key, value);
720 	if (sccp_strlen_zero(family) || sccp_strlen_zero(key) || sccp_strlen_zero(value)) {
721 		return FALSE;
722 	}
723 	res = ast_db_put(family, key, value);
724 	return (!res) ? TRUE : FALSE;
725 }
726 
sccp_astwrap_getFromDatabase(const char * family,const char * key,char * out,int outlen)727 boolean_t sccp_astwrap_getFromDatabase(const char *family, const char *key, char *out, int outlen)
728 {
729 	int res;
730 
731 	// pbx_log(LOG_NOTICE, "family:%s, key:%s\n", family, key);
732 	if (sccp_strlen_zero(family) || sccp_strlen_zero(key)) {
733 		return FALSE;
734 	}
735 	res = ast_db_get(family, key, out, outlen);
736 	return (!res) ? TRUE : FALSE;
737 }
738 
sccp_astwrap_removeFromDatabase(const char * family,const char * key)739 boolean_t sccp_astwrap_removeFromDatabase(const char *family, const char *key)
740 {
741 	int res;
742 
743 	// pbx_log(LOG_NOTICE, "family:%s, key:%s\n", family, key);
744 	if (sccp_strlen_zero(family) || sccp_strlen_zero(key)) {
745 		return FALSE;
746 	}
747 	res = ast_db_del(family, key);
748 	return (!res) ? TRUE : FALSE;
749 }
750 
sccp_astwrap_removeTreeFromDatabase(const char * family,const char * key)751 boolean_t sccp_astwrap_removeTreeFromDatabase(const char *family, const char *key)
752 {
753 	int res;
754 
755 	// pbx_log(LOG_NOTICE, "family:%s, key:%s\n", family, key);
756 	if (sccp_strlen_zero(family) || sccp_strlen_zero(key)) {
757 		return FALSE;
758 	}
759 	res = ast_db_deltree(family, key);
760 	return (!res) ? TRUE : FALSE;
761 }
762 
763 /* end - database */
764 
765 /*!
766  * \brief Turn on music on hold on a given channel
767  * \note replacement for ast_moh_start
768  *
769  * \param pbx_channel The channel structure that will get music on hold
770  * \param mclass The class to use if the musicclass is not currently set on the channel structure.
771  * \param interpclass The class to use if the musicclass is not currently set on the channel structure or in the mclass argument.
772  *
773  * \retval Zero on success
774  * \retval non-zero on failure
775  */
sccp_astwrap_moh_start(PBX_CHANNEL_TYPE * pbx_channel,const char * mclass,const char * interpclass)776 int sccp_astwrap_moh_start(PBX_CHANNEL_TYPE * pbx_channel, const char *mclass, const char *interpclass)
777 {
778 	if (!pbx_test_flag(pbx_channel_flags(pbx_channel), AST_FLAG_MOH)) {
779 		pbx_set_flag(pbx_channel_flags(pbx_channel), AST_FLAG_MOH);
780 		return ast_moh_start( pbx_channel, mclass, interpclass);
781 	}
782 	return 0;
783 }
784 
sccp_astwrap_moh_stop(PBX_CHANNEL_TYPE * pbx_channel)785 void sccp_astwrap_moh_stop(PBX_CHANNEL_TYPE * pbx_channel)
786 {
787 	if (pbx_test_flag(pbx_channel_flags(pbx_channel), AST_FLAG_MOH)) {
788 		pbx_clear_flag(pbx_channel_flags(pbx_channel), AST_FLAG_MOH);
789 		ast_moh_stop( pbx_channel);
790 	}
791 }
792 
sccp_astwrap_redirectedUpdate(sccp_channel_t * channel,const void * data,size_t datalen)793 void sccp_astwrap_redirectedUpdate(sccp_channel_t * channel, const void *data, size_t datalen)
794 {
795 	PBX_CHANNEL_TYPE *ast = channel->owner;
796 	int redirectreason = 0;
797 	sccp_callinfo_t *ci = sccp_channel_getCallInfo(channel);
798 
799 	iCallInfo.Getter(ci,
800 		SCCP_CALLINFO_LAST_REDIRECT_REASON, &redirectreason,
801 		SCCP_CALLINFO_KEY_SENTINEL);
802 #if ASTERISK_VERSION_GROUP >106
803 	struct ast_party_id redirecting_from = pbx_channel_redirecting_effective_from(ast);
804 	struct ast_party_id redirecting_to = pbx_channel_redirecting_effective_to(ast);
805 
806 	sccp_log((DEBUGCAT_PBX)) (VERBOSE_PREFIX_3 "%s: Got redirecting update. From %s<%s>; To %s<%s>\n", pbx_channel_name(ast),
807 				(redirecting_from.name.valid && redirecting_from.name.str) ? redirecting_from.name.str : "",
808 				(redirecting_from.number.valid && redirecting_from.number.str) ? redirecting_from.number.str : "",
809 				(redirecting_to.name.valid && redirecting_to.name.str) ? redirecting_to.name.str : "",
810 				(redirecting_to.number.valid && redirecting_to.number.str) ? redirecting_to.number.str : "");
811 
812 	iCallInfo.Setter(ci,
813 		SCCP_CALLINFO_LAST_REDIRECTINGPARTY_NAME, redirecting_from.name.valid && redirecting_from.name.str ? redirecting_from.name.str : NULL,
814 		SCCP_CALLINFO_LAST_REDIRECTINGPARTY_NUMBER, (redirecting_from.number.valid && redirecting_from.number.str) ? redirecting_from.number.str : "",
815 		SCCP_CALLINFO_ORIG_CALLEDPARTY_NUMBER, (redirecting_from.number.valid && redirecting_from.number.str) ? redirecting_from.number.str : "",
816 		SCCP_CALLINFO_ORIG_CALLEDPARTY_NAME, redirecting_from.name.valid && redirecting_from.name.str ? redirecting_from.name.str : NULL,
817 		SCCP_CALLINFO_ORIG_CALLEDPARTY_REDIRECT_REASON, redirectreason,
818 		SCCP_CALLINFO_LAST_REDIRECT_REASON, 4,					// need to figure out these codes
819 		SCCP_CALLINFO_KEY_SENTINEL);
820 
821 #else
822 	sccp_log((DEBUGCAT_PBX)) (VERBOSE_PREFIX_3 "%s: Got redirecting update. From <%s>\n", pbx_channel_name(ast), ast->cid.cid_rdnis);
823 	iCallInfo.Setter(ci,
824 		SCCP_CALLINFO_LAST_REDIRECTINGPARTY_NUMBER, ast->cid.cid_rdnis ? ast->cid.cid_rdnis : "",
825 		SCCP_CALLINFO_ORIG_CALLEDPARTY_NUMBER, ast->cid.cid_rdnis ? ast->cid.cid_rdnis : NULL,
826 		SCCP_CALLINFO_ORIG_CALLEDPARTY_REDIRECT_REASON, redirectreason,
827 		SCCP_CALLINFO_LAST_REDIRECT_REASON, 4,					// need to figure out these codes
828 		SCCP_CALLINFO_KEY_SENTINEL);
829 #endif
830 
831 	//sccp_channel_display_callInfo(channel);
832 	sccp_channel_send_callinfo2(channel);
833 }
834 
835 /*!
836  * \brief Update Connected Line
837  * \param channel Asterisk Channel as ast_channel
838  * \param data Asterisk Data
839  * \param datalen Asterisk Data Length
840  */
sccp_astwrap_connectedline(sccp_channel_t * channel,const void * data,size_t datalen)841 void sccp_astwrap_connectedline(sccp_channel_t * channel, const void *data, size_t datalen)
842 {
843 #if ASTERISK_VERSION_GROUP > 106
844 	PBX_CHANNEL_TYPE *ast = channel->owner;
845 	int changes = 0;
846 	sccp_callinfo_t *const callInfo = sccp_channel_getCallInfo(channel);
847 
848 	sccp_log((DEBUGCAT_PBX)) (VERBOSE_PREFIX_3 "%s: %s call Got connected line update, connected.id.number=%s, connected.id.name=%s, source=%s\n",
849 		channel->calltype == SKINNY_CALLTYPE_INBOUND ? "INBOUND" : "OUTBOUND",
850 		pbx_channel_name(ast),
851 		pbx_channel_connected_id(ast).number.str ? pbx_channel_connected_id(ast).number.str : "(nil)",
852 		pbx_channel_connected_id(ast).name.str ? pbx_channel_connected_id(ast).name.str : "(nil)",
853 		pbx_connected_line_source_name(pbx_channel_connected_source(ast))
854 	);
855 
856 	char tmpCallingNumber[StationMaxDirnumSize] = {0};
857 	char tmpCallingName[StationMaxNameSize] = {0};
858 	char tmpCalledNumber[StationMaxDirnumSize] = {0};
859 	char tmpCalledName[StationMaxNameSize] = {0};
860 	char tmpOrigCalledPartyNumber[StationMaxDirnumSize] = {0};
861 	char tmpOrigCalledPartyName[StationMaxNameSize] = {0};
862 	int tmpOrigCalledPartyRedirectReason = 0;
863 	int tmpLastRedirectReason = 4;		/* \todo need to figure out more about these codes */
864 
865 	iCallInfo.Getter(callInfo,
866 		SCCP_CALLINFO_CALLINGPARTY_NUMBER, &tmpCallingNumber,
867 		SCCP_CALLINFO_CALLINGPARTY_NAME, &tmpCallingName,
868 		SCCP_CALLINFO_CALLEDPARTY_NUMBER, &tmpCalledNumber,
869 		SCCP_CALLINFO_CALLEDPARTY_NAME, &tmpCalledName,
870 		SCCP_CALLINFO_ORIG_CALLEDPARTY_NUMBER, &tmpOrigCalledPartyNumber,
871 		SCCP_CALLINFO_ORIG_CALLEDPARTY_NAME, &tmpOrigCalledPartyName,
872 		SCCP_CALLINFO_ORIG_CALLEDPARTY_REDIRECT_REASON, &tmpOrigCalledPartyRedirectReason,
873 		SCCP_CALLINFO_KEY_SENTINEL);
874 
875 	if (SCCP_CHANNELSTATE_CALLPARK == channel->state && !sccp_strlen_zero (pbx_builtin_getvar_helper (channel->owner, "PARKER"))) {
876 		channel->calltype = SKINNY_CALLTYPE_OUTBOUND;
877 		sccp_channel_setChannelstate (channel, SCCP_CHANNELSTATE_RINGOUT);
878 	}
879 
880 	/* set the original calling/called party if the reason is a transfer */
881 	if (channel->calltype == SKINNY_CALLTYPE_INBOUND) {
882 		if (pbx_channel_connected_source(ast) == AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER || pbx_channel_connected_source(ast) == AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING) {
883 			// sccp_log(DEBUGCAT_CHANNEL) ("SCCP: (connectedline) Transfer Destination\n");
884 			changes = iCallInfo.Setter(callInfo,
885 				SCCP_CALLINFO_CALLINGPARTY_NUMBER, pbx_channel_connected_id(ast).number.str,
886 				SCCP_CALLINFO_CALLINGPARTY_NAME, pbx_channel_connected_id(ast).name.str,
887 
888 				SCCP_CALLINFO_ORIG_CALLINGPARTY_NUMBER, pbx_channel_connected_id(ast).number.str,
889 				SCCP_CALLINFO_ORIG_CALLINGPARTY_NAME, pbx_channel_connected_id(ast).name.str,
890 
891 				SCCP_CALLINFO_ORIG_CALLEDPARTY_NUMBER, tmpCallingNumber,
892 				SCCP_CALLINFO_ORIG_CALLEDPARTY_NAME, tmpCallingName,
893 				SCCP_CALLINFO_ORIG_CALLEDPARTY_REDIRECT_REASON, tmpOrigCalledPartyRedirectReason,
894 
895 				SCCP_CALLINFO_LAST_REDIRECTINGPARTY_NUMBER, tmpCallingNumber,
896 				SCCP_CALLINFO_LAST_REDIRECTINGPARTY_NAME, tmpCallingNumber,
897 				SCCP_CALLINFO_LAST_REDIRECT_REASON, tmpLastRedirectReason,
898 
899 				SCCP_CALLINFO_KEY_SENTINEL);
900 		} else {
901 #if ASTERISK_VERSION_GROUP >= 111
902 			struct ast_party_id redirecting_orig = pbx_channel_redirecting_effective_orig(ast);
903 			if (redirecting_orig.name.valid || redirecting_orig.number.valid) {
904 				changes = iCallInfo.Setter(callInfo,
905 					SCCP_CALLINFO_CALLINGPARTY_NUMBER, pbx_channel_connected_id(ast).number.str,
906 					SCCP_CALLINFO_CALLINGPARTY_NAME, pbx_channel_connected_id(ast).name.str,
907 					SCCP_CALLINFO_ORIG_CALLEDPARTY_NAME, redirecting_orig.name.valid ? ast_channel_redirecting(ast)->orig.name.str : "",
908 					SCCP_CALLINFO_ORIG_CALLEDPARTY_NUMBER, redirecting_orig.number.valid ? ast_channel_redirecting(ast)->orig.number.str : "",
909 					SCCP_CALLINFO_KEY_SENTINEL);
910 			} else
911 #endif
912 			{
913 				changes = iCallInfo.Setter(callInfo,
914 					SCCP_CALLINFO_CALLINGPARTY_NUMBER, pbx_channel_connected_id(ast).number.str,
915 					SCCP_CALLINFO_CALLINGPARTY_NAME, pbx_channel_connected_id(ast).name.str,
916 					SCCP_CALLINFO_KEY_SENTINEL);
917 			}
918 			sccp_indicate (NULL, channel, channel->state);
919 		}
920 	} else /* OUTBOUND CALL */ {
921 		if (sccp_strlen_zero(pbx_builtin_getvar_helper(ast, "SETCALLEDPARTY"))) {
922 			struct ast_party_id connected = pbx_channel_connected_id(ast);
923 			changes = iCallInfo.Setter(callInfo,
924 				SCCP_CALLINFO_CALLEDPARTY_NUMBER, connected.number.valid ? connected.number.str : tmpCalledNumber,
925 				SCCP_CALLINFO_CALLEDPARTY_NAME, connected.name.valid ? connected.name.str : tmpCalledName,
926 				SCCP_CALLINFO_ORIG_CALLEDPARTY_NUMBER, (!sccp_strlen_zero(tmpOrigCalledPartyNumber)) ? tmpOrigCalledPartyNumber : (!sccp_strlen_zero(tmpCalledNumber) ? tmpCalledNumber : connected.number.str),
927 				SCCP_CALLINFO_ORIG_CALLEDPARTY_NAME, (!sccp_strlen_zero(tmpOrigCalledPartyName)) ? tmpOrigCalledPartyName : (!sccp_strlen_zero(tmpCalledName) ? tmpCalledName : connected.name.str),
928 				SCCP_CALLINFO_KEY_SENTINEL);
929 		}
930 	}
931 	//sccp_channel_display_callInfo(channel);
932 	if (changes) {
933 		sccp_channel_send_callinfo2(channel);
934 
935 		/* We have a preliminary connected line, indicate RINGOUT_ALERTING */
936 		if (SKINNY_CALLTYPE_OUTBOUND == channel->calltype && SCCP_CHANNELSTATE_RINGOUT == channel->state) {
937 			sccp_indicate(NULL, channel, SCCP_CHANNELSTATE_RINGOUT_ALERTING);
938 		}
939 #if CS_SCCP_VIDEO
940 		const char *VideoStr = pbx_builtin_getvar_helper(channel->owner, "SCCP_VIDEO_MODE");
941 		if (VideoStr && !sccp_strlen_zero(VideoStr)) {
942 			sccp_channel_setVideoMode(channel, VideoStr);
943 		}
944 #endif
945         }
946 	if (SCCP_CHANNELSTATE_CALLPARK == channel->state || !sccp_strlen_zero (pbx_builtin_getvar_helper (channel->owner, "PARK_RETRIEVER"))) {
947 		sccp_indicate_force (NULL, channel, SCCP_CHANNELSTATE_CONNECTED);
948 	}
949 #endif
950 }
951 
sccp_astwrap_sendRedirectedUpdate(const sccp_channel_t * channel,const char * fromNumber,const char * fromName,const char * toNumber,const char * toName,uint8_t reason)952 void sccp_astwrap_sendRedirectedUpdate(const sccp_channel_t * channel, const char *fromNumber, const char *fromName, const char *toNumber, const char *toName, uint8_t reason)
953 {
954 #if ASTERISK_VERSION_GROUP >106
955 	struct ast_party_redirecting redirecting;
956 	struct ast_set_party_redirecting update_redirecting;
957 
958 	sccp_log((DEBUGCAT_PBX)) (VERBOSE_PREFIX_3 "%s: Send Redirected Update. From %s<%s>, To: %s<%s>\n", channel->designator, fromName, fromNumber, toName, toNumber);
959 
960 	ast_party_redirecting_init(&redirecting);
961 	memset(&update_redirecting, 0, sizeof(update_redirecting));
962 
963 	/* update redirecting info line for source part */
964 	if (fromNumber) {
965 		update_redirecting.from.number = 1;
966 		redirecting.from.number.valid = 1;
967 		redirecting.from.number.str = pbx_strdup(fromNumber);
968 	}
969 
970 	if (fromName) {
971 		update_redirecting.from.name = 1;
972 		redirecting.from.name.valid = 1;
973 		redirecting.from.name.str = pbx_strdup(fromName);
974 	}
975 
976 	if (toNumber) {
977 		update_redirecting.to.number = 1;
978 		redirecting.to.number.valid = 1;
979 		redirecting.to.number.str = pbx_strdup(toNumber);
980 	}
981 
982 	if (toName) {
983 		update_redirecting.to.name = 1;
984 		redirecting.to.name.valid = 1;
985 		redirecting.to.name.str = pbx_strdup(toName);
986 	}
987 #if ASTERISK_VERSION_GROUP >111
988 	redirecting.reason.code = reason;
989 #else
990 	redirecting.reason = reason;
991 #endif
992 
993 	ast_channel_queue_redirecting_update(channel->owner, &redirecting, &update_redirecting);
994 	ast_party_redirecting_free(&redirecting);
995 #else
996 	// set redirecting party (forwarder)
997 	if (fromNumber) {
998 		if (channel->owner->cid.cid_rdnis) {
999 			ast_free(channel->owner->cid.cid_rdnis);
1000 		}
1001 		channel->owner->cid.cid_rdnis = pbx_strdup(fromNumber);
1002 	}
1003 	// where is the call going to now
1004 	if (toNumber) {
1005 		if (channel->owner->cid.cid_dnid) {
1006 			ast_free(channel->owner->cid.cid_dnid);
1007 		}
1008 		channel->owner->cid.cid_dnid = pbx_strdup(toNumber);
1009 	}
1010 #endif
1011 }
1012 
1013 
sccp_parse_alertinfo(PBX_CHANNEL_TYPE * pbx_channel,skinny_ringtype_t * ringermode)1014 int sccp_parse_alertinfo(PBX_CHANNEL_TYPE *pbx_channel, skinny_ringtype_t *ringermode)
1015 {
1016 	int res = 0;
1017 	const char *alert_info = pbx_builtin_getvar_helper(pbx_channel, "ALERT_INFO");
1018 	if (alert_info && !sccp_strlen_zero(alert_info)) {
1019 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: Found ALERT_INFO=%s\n", pbx_channel_name(pbx_channel), alert_info);
1020 		if (!strncasecmp(alert_info, "bellcore-dr", 11) && strlen(alert_info) >= 12) {
1021 			switch(alert_info[11]) {
1022 				case '1':
1023 					*ringermode = SKINNY_RINGTYPE_INSIDE;
1024 					break;
1025 				case '2':
1026 					*ringermode = SKINNY_RINGTYPE_OUTSIDE;
1027 					break;
1028 				case '3':
1029 					*ringermode = SKINNY_RINGTYPE_FEATURE;
1030 					break;
1031 				case '4':
1032 					*ringermode = SKINNY_RINGTYPE_BELLCORE_4;
1033 					break;
1034 				case '5':
1035 					*ringermode = SKINNY_RINGTYPE_URGENT;
1036 					break;
1037 				default:
1038 					pbx_log(LOG_NOTICE, "%s: ALERT_INFO:%s could not be mapped to skinny ringtype\n", pbx_channel_name(pbx_channel), alert_info);
1039 					*ringermode = SKINNY_RINGTYPE_SENTINEL;
1040 					res = -1;
1041 					break;
1042 			}
1043 		} else {
1044 			*ringermode = skinny_ringtype_str2val(alert_info);
1045 		}
1046 	}
1047 	if (*ringermode == SKINNY_RINGTYPE_SENTINEL) {
1048 		*ringermode = GLOB(ringtype);
1049 	}
1050 	return res;
1051 }
1052 
sccp_parse_auto_answer(PBX_CHANNEL_TYPE * pbx_channel,sccp_autoanswer_t * autoanswer_type)1053 int sccp_parse_auto_answer(PBX_CHANNEL_TYPE * pbx_channel, sccp_autoanswer_t * autoanswer_type)
1054 {
1055 	int res = 0;
1056 	const char * auto_answer = pbx_builtin_getvar_helper(pbx_channel, "AUTO_ANSWER");
1057 	if (auto_answer && !sccp_strlen_zero(auto_answer)) {
1058 		sccp_log((DEBUGCAT_CORE))(VERBOSE_PREFIX_3 "%s: Found AUTO_ANSWER=%s\n", pbx_channel_name(pbx_channel), auto_answer);
1059 		if (sccp_strcaseequals(auto_answer, "1way") || sccp_strcaseequals(auto_answer, "1w")) {
1060 			*autoanswer_type = SCCP_AUTOANSWER_1W;
1061 		} else if (sccp_strcaseequals(auto_answer, "2way") || sccp_strcaseequals(auto_answer, "2w")) {
1062 			*autoanswer_type = SCCP_AUTOANSWER_2W;
1063 		} else {
1064 			res = -1;
1065 		}
1066 	}
1067 	return res;
1068 }
1069 
1070 /*!
1071  * parse the DIAL options and store results by ref
1072  */
sccp_parse_dial_options(char * options,sccp_autoanswer_t * autoanswer_type,uint8_t * autoanswer_cause,skinny_ringtype_t * ringermode)1073 int sccp_parse_dial_options(char *options, sccp_autoanswer_t *autoanswer_type, uint8_t *autoanswer_cause, skinny_ringtype_t *ringermode)
1074 {
1075 	int res = 0;
1076 	int optc = 0;
1077 	char *optv[5];
1078 	int opti = 0;
1079 
1080 	/* parse options */
1081 	if (options && (optc = sccp_app_separate_args(options, '/', optv, sizeof(optv) / sizeof(optv[0])))) {
1082 		for (opti = 0; opti < optc; opti++) {
1083 			if (!strncasecmp(optv[opti], "aa", 2)) {
1084 				/* let's use the old style auto answer aa1w and aa2w */
1085 				if (!strncasecmp(optv[opti], "aa1w", 4)) {
1086 					*autoanswer_type = SCCP_AUTOANSWER_1W;
1087 					optv[opti] += 4;
1088 				} else if (!strncasecmp(optv[opti], "aa2w", 4)) {
1089 					*autoanswer_type = SCCP_AUTOANSWER_2W;
1090 					optv[opti] += 4;
1091 				} else if (!strncasecmp(optv[opti], "aa=", 3)) {
1092 					optv[opti] += 3;
1093 					pbx_log(LOG_NOTICE, "parsing aa\n");
1094 					if (!strncasecmp(optv[opti], "1w", 2)) {
1095 						*autoanswer_type = SCCP_AUTOANSWER_1W;
1096 						optv[opti] += 2;
1097 					} else if (!strncasecmp(optv[opti], "2w", 2)) {
1098 						*autoanswer_type = SCCP_AUTOANSWER_2W;
1099 						pbx_log(LOG_NOTICE, "set aa to 2w\n");
1100 						optv[opti] += 2;
1101 					}
1102 				}
1103 
1104 				/* since the pbx ignores autoanswer_cause unless SCCP_RWLIST_GETSIZE(&l->channels) > 1, it is safe to set it if provided */
1105 				if (!sccp_strlen_zero(optv[opti]) && (autoanswer_cause)) {
1106 					if (!strcasecmp(optv[opti], "b")) {
1107 						*autoanswer_cause = AST_CAUSE_BUSY;
1108 					} else if (!strcasecmp(optv[opti], "u")) {
1109 						*autoanswer_cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
1110 					} else if (!strcasecmp(optv[opti], "c")) {
1111 						*autoanswer_cause = AST_CAUSE_CONGESTION;
1112 					}
1113 				}
1114 				/* check for ringer options */
1115 			} else if (!strncasecmp(optv[opti], "ringer=", 7)) {
1116 				optv[opti] += 7;
1117 				*ringermode = skinny_ringtype_str2val(optv[opti]);
1118 			} else {
1119 				pbx_log(LOG_WARNING, "SCCP: Unknown option %s\n", optv[opti]);
1120 				res = -1;
1121 			}
1122 		}
1123 	}
1124 	if (*ringermode == SKINNY_RINGTYPE_SENTINEL) {
1125 		*ringermode = GLOB(ringtype);
1126 	}
1127 	return res;
1128 }
1129 
1130 /*!
1131  * \brief ACF Channel Read callback
1132  *
1133  * \param ast Asterisk Channel
1134  * \param funcname      functionname as const char *
1135  * \param preparse      arguments as char *
1136  * \param buf           buffer as char *
1137  * \param buflen        bufferlenght as size_t
1138  * \return result as int
1139  *
1140  * \called_from_asterisk
1141  */
sccp_astgenwrap_channel_read(PBX_CHANNEL_TYPE * ast,NEWCONST char * funcname,char * preparse,char * buf,size_t buflen)1142 int sccp_astgenwrap_channel_read(PBX_CHANNEL_TYPE * ast, NEWCONST char *funcname, char *preparse, char *buf, size_t buflen)
1143 {
1144 	int res = -1;
1145 
1146 	char *parse = pbx_strdupa(preparse);
1147 
1148 	AST_DECLARE_APP_ARGS(args, AST_APP_ARG(param); AST_APP_ARG(type); AST_APP_ARG(field););
1149 	AST_STANDARD_APP_ARGS(args, parse);
1150 
1151 	/* begin asserts */
1152 	if (!ast || !CS_AST_CHANNEL_PVT_IS_SCCP(ast)) {
1153 		pbx_log(LOG_ERROR, "This function requires a valid SCCP channel\n");
1154 		return -1;
1155 	}
1156 
1157 	AUTO_RELEASE(sccp_channel_t, c , get_sccp_channel_from_pbx_channel(ast));
1158 	if (!c) {
1159 		return -1;
1160 	}
1161 	AUTO_RELEASE(sccp_device_t, d , sccp_channel_getDevice(c));
1162 	if (!d) {
1163 		return -1;
1164 	}
1165 	/* end asserts */
1166 
1167 	/* handle params */
1168 	if (!strcasecmp(args.param, "peerip")) {
1169 		struct sockaddr_storage sas = { 0 };
1170 		if (sccp_session_getOurIP(d->session, &sas, 0)) {
1171 			sccp_copy_string(buf, sccp_netsock_stringify(&sas), buflen);
1172 		} else {
1173 			sccp_copy_string(buf, "--", buflen);
1174 		}
1175 	} else if (!strcasecmp(args.param, "recvip")) {
1176 		struct sockaddr_storage sas = { 0 };
1177 		if (sccp_session_getSas(d->session, &sas)) {
1178 			sccp_copy_string(buf, sccp_netsock_stringify(&sas), buflen);
1179 		} else {
1180 			sccp_copy_string(buf, "--", buflen);
1181 		}
1182 	} else if (sccp_strcaseequals(args.type, "codec")) {
1183 		sccp_codec_multiple2str (buf, buflen - 1, c->capabilities.audio, SKINNY_MAX_CAPABILITIES);
1184 		sccp_codec_multiple2str (buf, buflen - 1, c->preferences.audio, SKINNY_MAX_CAPABILITIES);
1185 #if CS_SCCP_VIDEO
1186 		sccp_codec_multiple2str (buf, buflen - 1, c->capabilities.video, SKINNY_MAX_CAPABILITIES);
1187 		sccp_codec_multiple2str (buf, buflen - 1, c->preferences.video, SKINNY_MAX_CAPABILITIES);
1188 #endif
1189 	} else if (sccp_strcaseequals(args.type, "video")) {
1190 #if CS_SCCP_VIDEO
1191 		sccp_copy_string(buf, sccp_video_mode2str(c->videomode), buflen);
1192 #endif
1193 	} else if (!strcasecmp(args.param, "useragent")) {
1194 		sccp_copy_string(buf, skinny_devicetype2str(d->skinny_type), buflen);
1195 	} else if (!strcasecmp(args.param, "from")) {
1196 		sccp_copy_string(buf, (char *) d->id, buflen);
1197 #if ASTERISK_VERSION_GROUP >= 108
1198 	} else if (!strcasecmp(args.param, "rtpqos")) {
1199 		PBX_RTP_TYPE *rtp = NULL;
1200 
1201 		if (sccp_strlen_zero(args.type)) {
1202 			args.type = pbx_strdupa("audio");
1203 		}
1204 
1205 		if (sccp_strcaseequals(args.type, "audio")) {
1206 			rtp = c->rtp.audio.instance;
1207 		} else if (sccp_strcaseequals(args.type, "video")) {
1208 			rtp = c->rtp.video.instance;
1209 		/*
1210 		} else if (sccp_strcaseequals(args.type, "text")) {
1211 			rtp = c->rtp.text.instance;
1212 		*/
1213 		} else {
1214 			return -1;
1215 		}
1216 		ast_channel_lock(ast);
1217 		do {
1218 			if (rtp) {
1219 				if (sccp_strlen_zero(args.field) || sccp_strcaseequals(args.field, "all")) {
1220 					char quality_buf[256 /*AST_MAX_USER_FIELD */ ];
1221 
1222 					if (!ast_rtp_instance_get_quality(rtp, AST_RTP_INSTANCE_STAT_FIELD_QUALITY, quality_buf, sizeof(quality_buf))) {
1223 						break;
1224 					}
1225 
1226 					sccp_copy_string(buf, quality_buf, buflen);
1227 					res = 0;
1228 					break;
1229 				}
1230 				struct ast_rtp_instance_stats stats;
1231 				int i;
1232 				enum __int_double { __INT, __DBL };
1233 				struct {
1234 					const char *name;
1235 					enum __int_double type;
1236 					union {
1237 						unsigned int *i4;
1238 						double *d8;
1239 					};
1240 				} lookup[] = {
1241 					/* *INDENT-OFF* */
1242 					{"txcount", 		__INT, {.i4 = &stats.txcount},},
1243 					{"rxcount", 		__INT, {.i4 = &stats.rxcount,},},
1244 					{"txjitter", 		__DBL, {.d8 = &stats.txjitter,},},
1245 					{"rxjitter", 		__DBL, {.d8 = &stats.rxjitter,},},
1246 					{"remote_maxjitter", 	__DBL, {.d8 = &stats.remote_maxjitter,},},
1247 					{"remote_minjitter", 	__DBL, {.d8 = &stats.remote_minjitter,},},
1248 					{"remote_normdevjitter",__DBL, {.d8 = &stats.remote_normdevjitter,},},
1249 					{"remote_stdevjitter", 	__DBL, {.d8 = &stats.remote_stdevjitter,},},
1250 					{"local_maxjitter",	__DBL, {.d8 = &stats.local_maxjitter,},},
1251 					{"local_minjitter", 	__DBL, {.d8 = &stats.local_minjitter,},},
1252 					{"local_normdevjitter", __DBL, {.d8 = &stats.local_normdevjitter,},},
1253 					{"local_stdevjitter", 	__DBL, {.d8 = &stats.local_stdevjitter,},},
1254 					{"txploss", 		__INT, {.i4 = &stats.txploss,},},
1255 					{"rxploss", 		__INT, {.i4 = &stats.rxploss,},},
1256 					{"remote_maxrxploss", 	__DBL, {.d8 = &stats.remote_maxrxploss,},},
1257 					{"remote_minrxploss", 	__DBL, {.d8 = &stats.remote_minrxploss,},},
1258 					{"remote_normdevrxploss",__DBL, {.d8 = &stats.remote_normdevrxploss,},},
1259 					{"remote_stdevrxploss", __DBL, {.d8 = &stats.remote_stdevrxploss,},},
1260 					{"local_maxrxploss", 	__DBL, {.d8 = &stats.local_maxrxploss,},},
1261 					{"local_minrxploss", 	__DBL, {.d8 = &stats.local_minrxploss,},},
1262 					{"local_normdevrxploss",__DBL, {.d8 = &stats.local_normdevrxploss,},},
1263 					{"local_stdevrxploss", 	__DBL, {.d8 = &stats.local_stdevrxploss,},},
1264 					{"rtt", 		__DBL, {.d8 = &stats.rtt,},},
1265 					{"maxrtt", 		__DBL, {.d8 = &stats.maxrtt,},},
1266 					{"minrtt", 		__DBL, {.d8 = &stats.minrtt,},},
1267 					{"normdevrtt", 		__DBL, {.d8 = &stats.normdevrtt,},},
1268 					{"stdevrtt", 		__DBL, {.d8 = &stats.stdevrtt,},},
1269 					{"local_ssrc", 		__INT, {.i4 = &stats.local_ssrc,},},
1270 					{"remote_ssrc", 	__INT, {.i4 = &stats.remote_ssrc,},},
1271 					{NULL,},
1272 					/* *INDENT-ON* */
1273 				};
1274 
1275 				if (ast_rtp_instance_get_stats(rtp, &stats, AST_RTP_INSTANCE_STAT_ALL)) {
1276 					break;
1277 				}
1278 
1279 				for (i = 0; !sccp_strlen_zero(lookup[i].name); i++) {
1280 					if (sccp_strcaseequals(args.field, lookup[i].name)) {
1281 						if (lookup[i].type == __INT) {
1282 							snprintf(buf, buflen, "%u", *lookup[i].i4);
1283 						} else {
1284 							snprintf(buf, buflen, "%f", *lookup[i].d8);
1285 						}
1286 						res = 0;
1287 						break;
1288 					}
1289 				}
1290 			}
1291 		} while (0);
1292 		ast_channel_unlock(ast);
1293 #endif
1294 	} else {
1295 		pbx_log(LOG_WARNING, "SCCP: (channel_read) Unrecognized argument '%s' to %s\n", preparse, funcname);
1296 	}
1297 	return res;
1298 }
1299 
sccp_astgenwrap_channel_write(PBX_CHANNEL_TYPE * ast,const char * funcname,char * args,const char * value)1300 int sccp_astgenwrap_channel_write(PBX_CHANNEL_TYPE * ast, const char *funcname, char *args, const char *value)
1301 {
1302 	int res = 0;
1303 
1304 	AUTO_RELEASE(sccp_channel_t, c , get_sccp_channel_from_pbx_channel(ast));
1305 	if (c) {
1306 		if (!strcasecmp(args, "MaxCallBR")) {
1307 			sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: set max call bitrate to %s\n", (char *) c->designator, value);
1308 
1309 			if (sscanf(value, "%ud", &c->maxBitRate)) {
1310 				pbx_builtin_setvar_helper(ast, "_MaxCallBR", value);
1311 			} else {
1312 				res = -1;
1313 			}
1314 
1315 		} else if (!strcasecmp(args, "codec")) {
1316 			res = (TRUE == sccp_channel_setPreferredCodec(c, value)) ? 0 : -1;
1317 
1318 		} else if (!strcasecmp(args, "video")) {
1319 			res = (TRUE == sccp_channel_setVideoMode(c, value)) ? 0 : -1;
1320 
1321 		} else if (!strcasecmp(args, "CallingParty")) {
1322 			if(!value || sccp_strlen_zero(value)) {
1323 				pbx_log(LOG_ERROR, "No valid party information provided: '%s'\n", value);
1324 				return -1;
1325 			}
1326 			char *num, *name;
1327 			pbx_callerid_parse((char *) value, &name, &num);
1328 			sccp_channel_set_callingparty(c, name, num);
1329 			sccp_channel_display_callInfo(c);
1330 			pbx_builtin_setvar_helper(c->owner, "SETCALLINGPARTY", pbx_strdup(value));
1331 		} else if (!strcasecmp(args, "CalledParty")) {
1332 			if(!value || sccp_strlen_zero(value)) {
1333 				pbx_log(LOG_ERROR, "No valid party information provided: '%s'\n", value);
1334 				return -1;
1335 			}
1336 			char *num, *name;
1337 			pbx_callerid_parse((char *) value, &name, &num);
1338 			sccp_channel_set_calledparty(c, name, num);
1339 			sccp_channel_display_callInfo(c);
1340 			pbx_builtin_setvar_helper(c->owner, "SETCALLEDPARTY", pbx_strdup(value));
1341 		} else if (!strcasecmp(args, "OriginalCallingParty")) {
1342 			if(!value || sccp_strlen_zero(value)) {
1343 				pbx_log(LOG_ERROR, "No valid party information provided: '%s'\n", value);
1344 				return -1;
1345 			}
1346 			char *num, *name;
1347 			pbx_callerid_parse((char *) value, &name, &num);
1348 			sccp_channel_set_originalCallingparty(c, name, num);
1349 			sccp_channel_display_callInfo(c);
1350 			pbx_builtin_setvar_helper(c->owner, "SETORIGCALLINGPARTY", pbx_strdup(value));
1351 		} else if (!strcasecmp(args, "OriginalCalledParty")) {
1352 			if(!value || sccp_strlen_zero(value)) {
1353 				pbx_log(LOG_ERROR, "No valid party information provided: '%s'\n", value);
1354 				return -1;
1355 			}
1356 			char *num, *name;
1357 			pbx_callerid_parse((char *) value, &name, &num);
1358 			sccp_channel_set_originalCalledparty(c, name, num);
1359 			sccp_channel_display_callInfo(c);
1360 			pbx_builtin_setvar_helper(c->owner, "SETORIGCALLEDPARTY", pbx_strdup(value));
1361 		} else if (!strcasecmp(args, "microphone")) {
1362 			if (!value || sccp_strlen_zero(value) || !sccp_true(value)) {
1363 				c->setMicrophone(c, FALSE);
1364 			} else {
1365 				c->setMicrophone(c, TRUE);
1366 			}
1367 		} else {
1368 			res = -1;
1369 		}
1370 	} else {
1371 		pbx_log(LOG_ERROR, "This function requires a valid SCCP channel\n");
1372 		res = -1;
1373 	}
1374 	return res;
1375 }
1376 
1377 /*!
1378  * \brief Call asterisk automon feature
1379  * \obsolete, using sccp_manager_action2str method instead
1380  */
sccp_astgenwrap_featureMonitor(const sccp_channel_t * channel)1381 boolean_t sccp_astgenwrap_featureMonitor(const sccp_channel_t * channel)
1382 {
1383 #if ASTERISK_VERSION_GROUP >= 112
1384 	char featexten[SCCP_MAX_EXTENSION] = "";
1385 
1386 	if (iPbx.getFeatureExtension(channel, "automon", featexten) && !sccp_strlen_zero(featexten)) {
1387 		pbx_log(LOG_ERROR, "%s: Sending DTMF:'%s' to switch Monitor Feature\n", channel->designator, featexten);
1388 		struct ast_frame f = { AST_FRAME_DTMF, };
1389 		uint j;
1390 
1391 		f.len = 100;
1392 		for (j = 0; j < strlen(featexten); j++) {
1393 			f.subclass.integer = featexten[j];
1394 			ast_queue_frame(channel->owner, &f);
1395 		}
1396 		return TRUE;
1397 	}
1398 	pbx_log(LOG_ERROR, "SCCP: Monitor Feature Extension Not available\n");
1399 	return FALSE;
1400 #else
1401 	ast_rdlock_call_features();
1402 	struct ast_call_feature *feature = ast_find_call_feature("automon");
1403 	ast_unlock_call_features();
1404 
1405 	if (feature) {
1406 		PBX_CHANNEL_TYPE *bridgePeer = iPbx.get_bridged_channel(channel->owner);
1407 		if (bridgePeer) {
1408 			feature->operation(channel->owner, bridgePeer, NULL, "monitor button", FEATURE_SENSE_CHAN | FEATURE_SENSE_PEER, NULL);
1409 			pbx_channel_unref(bridgePeer);
1410 		} else {
1411 			pbx_log(LOG_ERROR, "SCCP: No bridgepeer available\n");
1412 		}
1413 		return TRUE;
1414 	}
1415 	sccp_log(DEBUGCAT_CORE) (VERBOSE_PREFIX_3 "%s: Automon not available in features.conf\n", channel->designator);
1416 	return FALSE;
1417 #endif
1418 }
1419 
1420 #if !defined(AST_DEFAULT_EMULATE_DTMF_DURATION)
1421 #define AST_DEFAULT_EMULATE_DTMF_DURATION 100
1422 #endif
1423 #if ASTERISK_VERSION_GROUP > 106
sccp_wrapper_sendDigits(const sccp_channel_t * channel,const char * digits)1424 int sccp_wrapper_sendDigits(const sccp_channel_t * channel, const char *digits)
1425 {
1426 	uint8_t maxdigits = AST_MAX_EXTENSION;
1427 	if (!channel || !channel->owner) {
1428 		pbx_log(LOG_WARNING, "No channel to send digits to\n");
1429 		return 0;
1430 	}
1431 	if (!digits || sccp_strlen_zero(digits)) {
1432 		pbx_log(LOG_WARNING, "No digits to send\n");
1433 		return 0;
1434 	}
1435 	//ast_channel_undefer_dtmf(channel->owner);
1436 	PBX_CHANNEL_TYPE *pbx_channel = channel->owner;
1437 	PBX_FRAME_TYPE f = ast_null_frame;
1438 
1439 	sccp_log((DEBUGCAT_HIGH)) (VERBOSE_PREFIX_3 "%s: Sending digits '%s'\n", (char *) channel->currentDeviceId, digits);
1440 	// We don't just call sccp_pbx_senddigit due to potential overhead, and issues with locking
1441 	f.src = "SCCP";
1442 	while (maxdigits-- && *digits != '\0') {
1443 		sccp_log((DEBUGCAT_HIGH)) (VERBOSE_PREFIX_3 "%s: Sending digit %c\n", (char *) channel->currentDeviceId, *digits);
1444 
1445 		f.frametype = AST_FRAME_DTMF_END;								// Sending only the dmtf will force asterisk to start with DTMF_BEGIN and schedule the DTMF_END
1446 		f.subclass.integer = *digits;
1447 		// f.len = SCCP_MIN_DTMF_DURATION;
1448 		f.len = AST_DEFAULT_EMULATE_DTMF_DURATION;
1449 		f.src = "SEND DIGIT";
1450 		ast_queue_frame(pbx_channel, &f);
1451 		digits++;
1452 	}
1453 	return 1;
1454 }
1455 
sccp_wrapper_sendDigit(const sccp_channel_t * channel,const char digit)1456 int sccp_wrapper_sendDigit(const sccp_channel_t * channel, const char digit)
1457 {
1458 	const char digits[] = { digit, '\0' };
1459 	sccp_log((DEBUGCAT_HIGH)) (VERBOSE_PREFIX_3 "%s: got a single digit '%c' -> '%s'\n", channel->currentDeviceId, digit, digits);
1460 	return sccp_wrapper_sendDigits(channel, digits);
1461 }
1462 #endif
1463 
sccp_astwrap_doPickupThread(void * data)1464 static void *sccp_astwrap_doPickupThread(void *data)
1465 {
1466 	PBX_CHANNEL_TYPE *pbx_channel = (PBX_CHANNEL_TYPE *)data;
1467 
1468 	if (ast_pickup_call(pbx_channel)) {
1469 		pbx_channel_set_hangupcause(pbx_channel, AST_CAUSE_CALL_REJECTED);
1470 	} else {
1471 		pbx_channel_set_hangupcause(pbx_channel, AST_CAUSE_NORMAL_CLEARING);
1472 	}
1473 	ast_hangup(pbx_channel);
1474 	pbx_channel_unref(pbx_channel);
1475 	pbx_channel = NULL;
1476 	return NULL;
1477 }
1478 
sccp_astwrap_doPickup(PBX_CHANNEL_TYPE * pbx_channel)1479 static int sccp_astwrap_doPickup(PBX_CHANNEL_TYPE * pbx_channel)
1480 {
1481 	pthread_t threadid;
1482 
1483 	if (!pbx_channel || !(pbx_channel_ref(pbx_channel) > 0)) {
1484 		return FALSE;
1485 	}
1486 	if (ast_pthread_create_detached_background(&threadid, NULL, sccp_astwrap_doPickupThread, pbx_channel)) {
1487 		pbx_log(LOG_ERROR, "Unable to start Group pickup thread on channel %s\n", pbx_channel_name(pbx_channel));
1488 		pbx_channel_unref(pbx_channel);
1489 		return FALSE;
1490 	}
1491 	pbx_log(LOG_NOTICE, "SCCP: Started Group pickup thread on channel %s\n", pbx_channel_name(pbx_channel));
1492 	return TRUE;
1493 }
1494 
sccp_astgenwrap_set_callgroup(sccp_channel_t * channel,ast_group_t value)1495 void sccp_astgenwrap_set_callgroup(sccp_channel_t *channel, ast_group_t value)
1496 {
1497 	if (channel && channel->owner) {
1498 #if ASTERISK_VERSION_GROUP < 111
1499 		channel->owner->callgroup = value;
1500 #else
1501 		ast_channel_callgroup_set(channel->owner, value);
1502 #endif
1503 	}
1504 }
1505 
sccp_astgenwrap_set_pickupgroup(sccp_channel_t * channel,ast_group_t value)1506 void sccp_astgenwrap_set_pickupgroup(sccp_channel_t *channel, ast_group_t value)
1507 {
1508 	if (channel && channel->owner) {
1509 #if ASTERISK_VERSION_GROUP < 111
1510 		channel->owner->pickupgroup = value;
1511 #else
1512 		ast_channel_pickupgroup_set(channel->owner, value);
1513 #endif
1514 	}
1515 }
1516 
1517 #if CS_AST_HAS_NAMEDGROUP && ASTERISK_VERSION_GROUP >= 111
sccp_astgenwrap_set_named_callgroups(sccp_channel_t * channel,struct ast_namedgroups * value)1518 void sccp_astgenwrap_set_named_callgroups(sccp_channel_t *channel, struct ast_namedgroups *value)
1519 {
1520 	if (channel && channel->owner) {
1521 		ast_channel_named_callgroups_set(channel->owner, value);
1522 	}
1523 }
1524 
sccp_astgenwrap_set_named_pickupgroups(sccp_channel_t * channel,struct ast_namedgroups * value)1525 void sccp_astgenwrap_set_named_pickupgroups(sccp_channel_t *channel, struct ast_namedgroups *value)
1526 {
1527 	if (channel && channel->owner) {
1528 		ast_channel_named_pickupgroups_set(channel->owner, value);
1529 	}
1530 }
1531 #endif
1532 
pbx_pbx_start(PBX_CHANNEL_TYPE * pbx_channel)1533 enum ast_pbx_result pbx_pbx_start(PBX_CHANNEL_TYPE * pbx_channel)
1534 {
1535 	enum ast_pbx_result res = AST_PBX_FAILED;
1536 
1537 	if (!pbx_channel) {
1538 		pbx_log(LOG_ERROR, "SCCP: (pbx_pbx_start) called without pbx channel\n");
1539 		return res;
1540 	}
1541 
1542 	ast_channel_lock(pbx_channel);
1543 	AUTO_RELEASE(sccp_channel_t, channel , get_sccp_channel_from_pbx_channel(pbx_channel));
1544 	if (channel) {
1545 		// check if the pickup extension was entered
1546 		const char *dialedNumber = iPbx.getChannelExten(channel);
1547 		char pickupexten[SCCP_MAX_EXTENSION];
1548 
1549 		if (iPbx.getPickupExtension(channel, pickupexten) && sccp_strequals(dialedNumber, pickupexten)) {
1550 			if (sccp_astwrap_doPickup(pbx_channel)) {
1551 				res = AST_PBX_SUCCESS;
1552 			}
1553 			goto EXIT;
1554 		}
1555 		// channel->hangupRequest = sccp_astgenwrap_dummyHangup;
1556 		channel->hangupRequest = sccp_astgenwrap_carefullHangup;
1557 		res = ast_pbx_start(pbx_channel);								// starting ast_pbx_start with a locked ast_channel so we know exactly where we end up when/if the __ast_pbx_run get started
1558 		if (res == 0) {											// thread started successfully
1559 			do {											// wait for thread to become ready
1560 				pbx_safe_sleep(pbx_channel, 10);
1561 			} while (!pbx_channel_pbx(pbx_channel) && !pbx_check_hangup(pbx_channel));
1562 
1563 			if (pbx_channel_pbx(pbx_channel) && !pbx_check_hangup(pbx_channel)) {
1564 				sccp_log(DEBUGCAT_PBX) (VERBOSE_PREFIX_3 "%s: (pbx_pbx_start) autoloop has started, set requestHangup = requestQueueHangup\n", channel->designator);
1565 				channel->isRunningPbxThread = TRUE;
1566 				channel->hangupRequest = sccp_astgenwrap_requestQueueHangup;
1567 			} else {
1568 				pbx_log(LOG_NOTICE, "%s: (pbx_pbx_start) pbx_pbx_start thread is not running anymore, carefullHangup should remain. This channel will be hungup/being hungup soon\n", channel->designator);
1569 				res = AST_PBX_FAILED;
1570 			}
1571 		}
1572 	}
1573 EXIT:
1574 	ast_channel_unlock(pbx_channel);
1575 	return res;
1576 }
1577 
1578 // kate: indent-width 4; replace-tabs off; indent-mode cstyle; auto-insert-doxygen on; line-numbers on; tab-indents on; keep-extra-spaces off;
1579