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