1 /*!
2 * \file sccp_feature.c
3 * \brief SCCP Feature Class
4 * \author Federico Santulli <fsantulli [at] users.sourceforge.net >
5 * \author Diederik de Groot <ddegroot [at] users.sourceforge.net >
6 * \note This program is free software and may be modified and distributed under the terms of the GNU Public License.
7 * See the LICENSE file at the top of the source tree.
8 * \since 2009-01-16
9 *
10 */
11
12 /*!
13 * \remarks
14 * Purpose: SCCP Features
15 * When to use: Only methods directly related to handling phone features should be stored in this source file.
16 * Phone Features are Capabilities of the phone, like:
17 * - CallForwarding
18 * - Dialing
19 * - Changing to Do Not Disturb(DND) Status
20 * .
21 * Relations: These Features are called by FeatureButtons. Features can in turn call on Actions.
22 */
23
24 #include "config.h"
25 #include "common.h"
26 #include "sccp_channel.h"
27 #include "sccp_device.h"
28 #include "sccp_featureButton.h"
29 #include "sccp_feature.h"
30 #include "sccp_line.h"
31 #include "sccp_linedevice.h"
32 #include "sccp_pbx.h"
33 #include "sccp_conference.h"
34 #include "sccp_indicate.h"
35 #include "sccp_management.h"
36 #include "sccp_utils.h"
37 #include "sccp_labels.h"
38 #include "sccp_threadpool.h"
39
40 SCCP_FILE_VERSION(__FILE__, "");
41
42 #include <asterisk/causes.h> //AST_CAUSE_NORMAL_CLEARING
43
44 #if CS_SCCP_PICKUP
45 # if defined(CS_AST_DO_PICKUP) && defined(HAVE_PBX_FEATURES_H)
46 # include <asterisk/features.h>
47 # if ASTERISK_VERSION_GROUP >= 112
48 # include <asterisk/pickup.h>
49 # endif
50 # endif
51 #endif
52
53 /* forward declarations */
54 static int sccp_feat_sharedline_barge(constLineDevicePtr ld, channelPtr bargedChannel);
55
56 /*!
57 * \brief Handle Call Forwarding
58 * \param l SCCP Line
59 * \param device SCCP Device
60 * \param type CallForward Type (NONE, ALL, BUSY, NOANSWER) as SCCP_CFWD_*
61 * \return SCCP Channel
62 *
63 * \callgraph
64 * \callergraph
65 */
sccp_feat_handle_callforward(constLinePtr l,constDevicePtr d,sccp_cfwd_t type,channelPtr maybe_c,uint32_t lineInstance)66 void sccp_feat_handle_callforward(constLinePtr l, constDevicePtr d, sccp_cfwd_t type, channelPtr maybe_c, uint32_t lineInstance)
67 {
68 if (!l) {
69 pbx_log(LOG_ERROR, "SCCP: Can't allocate SCCP channel if line is not specified!\n");
70 return;
71 }
72
73 if (!d) {
74 pbx_log(LOG_ERROR, "SCCP: Can't allocate SCCP channel if device is not specified!\n");
75 return;
76 }
77
78 AUTO_RELEASE(sccp_linedevice_t, ld, sccp_linedevice_find(d, l));
79 if(!ld) {
80 pbx_log(LOG_ERROR, "%s: Device does not have line configured \n", DEV_ID_LOG(d));
81 return;
82 }
83
84 AUTO_RELEASE(sccp_channel_t, c , sccp_channel_getEmptyChannel(l, d, maybe_c, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL));
85 if (c) {
86 sccp_softswitch_t ss_action = c->softswitch_action ? c->softswitch_action : SCCP_SOFTSWITCH_GETFORWARDEXTEN;
87 if((ld->cfwd[SCCP_CFWD_ALL].enabled && type == SCCP_CFWD_ALL) || (ld->cfwd[SCCP_CFWD_BUSY].enabled && type == SCCP_CFWD_BUSY) || (ld->cfwd[SCCP_CFWD_NOANSWER].enabled && type == SCCP_CFWD_NOANSWER)) {
88 sccp_log(DEBUGCAT_PBX)("%s: Removing Call Forward\n", d->id);
89 ss_action = SCCP_SOFTSWITCH_ENDCALLFORWARD;
90 } else {
91 sccp_log(DEBUGCAT_PBX)("%s: Adding Call Forward\n", d->id);
92 }
93
94 if (ss_action == SCCP_SOFTSWITCH_GETFORWARDEXTEN) { // we already have an active channel
95 if (c->state == SCCP_CHANNELSTATE_RINGOUT || c->state == SCCP_CHANNELSTATE_CONNECTED || c->state == SCCP_CHANNELSTATE_PROCEED || c->state == SCCP_CHANNELSTATE_BUSY || c->state == SCCP_CHANNELSTATE_CONGESTION) {
96 if (c->calltype == SKINNY_CALLTYPE_OUTBOUND && !sccp_strlen_zero(c->dialedNumber)) { // if we have an outbound call, we can set callforward to dialed number -FS
97 sccp_line_cfwd(l, d, type, c->dialedNumber);
98 c->setTone(c, SKINNY_TONE_ZIP, SKINNY_TONEDIRECTION_USER);
99 sccp_channel_endcall(c);
100 return;
101 } else if(iPbx.channel_is_bridged(c)) { // check if we have an ast channel to get callerid from // if we have an incoming or
102 // forwarded call, let's get number from callerid :) -FS
103 char *number = NULL;
104 if (iPbx.get_callerid_name) {
105 iPbx.get_callerid_number(c->owner, &number);
106 }
107 if(number && !sccp_strlen_zero(number)) {
108 sccp_line_cfwd(l, d, type, number);
109 // we are on call, so no tone has been played until now :)
110 c->setTone(c, SKINNY_TONE_ZIP, SKINNY_TONEDIRECTION_USER);
111 sccp_channel_endcall(c);
112 sccp_free(number);
113 return;
114 }
115 }
116 }
117 }
118 c->softswitch_action = ss_action;
119 c->ss_data = type;
120 sccp_indicate(d, c, SCCP_CHANNELSTATE_GETDIGITS);
121 sccp_dev_set_message((devicePtr)d, SKINNY_DISP_ENTER_NUMBER_TO_FORWARD_TO, SCCP_DISPLAYSTATUS_TIMEOUT, FALSE, FALSE);
122 sccp_device_setLamp(d, sccp_cfwd2stimulus(type), ld->lineInstance, SKINNY_LAMP_FLASH);
123 if(ss_action == SCCP_SOFTSWITCH_ENDCALLFORWARD) {
124 sccp_pbx_softswitch(c);
125 }
126 }
127 }
128
129 #ifdef CS_SCCP_PICKUP
130 /*!
131 * sccp pickup helper function
132 * \note: function is called with target locked
133 */
sccp_feat_perform_pickup(constDevicePtr d,channelPtr c,PBX_CHANNEL_TYPE * target,boolean_t answer)134 static int sccp_feat_perform_pickup(constDevicePtr d, channelPtr c, PBX_CHANNEL_TYPE *target, boolean_t answer)
135 {
136 int res = 0;
137 pbx_assert(c != NULL);
138
139 #if CS_AST_DO_PICKUP
140 PBX_CHANNEL_TYPE *original = c->owner;
141 char * target_name = NULL;
142 char * target_number = NULL;
143 if (iPbx.get_callerid_name) {
144 iPbx.get_callerid_name(target, &target_name);
145 }
146 if (iPbx.get_callerid_number) {
147 iPbx.get_callerid_number(target, &target_number);
148 }
149
150 sccp_channel_stop_schedule_digittimout(c);
151 c->calltype = SKINNY_CALLTYPE_INBOUND; // reset call direction
152 c->state = SCCP_CHANNELSTATE_RINGING;
153 c->ringermode = answer ? SKINNY_RINGTYPE_SILENT : SKINNY_RINGTYPE_FEATURE;
154 int lineInstance = sccp_device_find_index_for_line(d, c->line->name);
155 if(c->line->pickup_modeanswer) {
156 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_RINGIN); // setting early to prevent getting multiple pickup button presses
157 }
158
159 char called_number[StationMaxDirnumSize] = { 0 };
160 char called_name[StationMaxNameSize] = { 0 };
161
162 /* Gather CallInfo */
163 sccp_callinfo_t * callinfo_orig = NULL;
164 callinfo_orig = sccp_channel_getCallInfo(c);
165 iCallInfo.Getter(callinfo_orig, // picker
166 SCCP_CALLINFO_CALLEDPARTY_NAME, &called_name, // name of picker
167 SCCP_CALLINFO_CALLEDPARTY_NUMBER, &called_number, SCCP_CALLINFO_KEY_SENTINEL);
168
169 {
170 // BTW: Remote end should change it's calltype for callinfo to FORWARD, upon pickup. Not sure how to inform them
171 // iCallInfo.Send(ci, c->callid, SKINNY_CALLTYPE_FORWARD, lineInstance, d, TRUE);
172 /*
173 struct ast_party_redirecting redirecting;
174 struct ast_set_party_redirecting update_redirecting;
175
176 ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(target));
177 memset(&update_redirecting, 0, sizeof(update_redirecting));
178 redirecting.to.number.valid = 1;
179 redirecting.to.number.str = called_number;
180 redirecting.to.name.valid = 1;
181 redirecting.to.name.str = called_name;
182 //redirecting.count = redirect->count;
183 ast_channel_set_redirecting(target, &redirecting, &update_redirecting);
184
185 ast_party_redirecting_free(&redirecting);
186 */
187 }
188
189 res = ast_do_pickup(original, target);
190 pbx_channel_unlock(target);
191 if(!res) { // directed pickup succeeded
192 sccp_log((DEBUGCAT_FEATURE))(VERBOSE_PREFIX_3 "%s: (perform_pickup) pickup succeeded on call: %s\n", DEV_ID_LOG(d), c->designator);
193 /* disconnect from masquaraded zombie channel */
194 sccp_channel_setDevice(c, NULL, FALSE);
195 pbx_channel_set_hangupcause(original, AST_CAUSE_ANSWERED_ELSEWHERE);
196
197 /* continue with masquaraded channel */
198 pbx_channel_set_hangupcause(c->owner, AST_CAUSE_NORMAL_CLEARING); // reset hangupcause up new channel
199 pbx_setstate(c->owner, AST_STATE_RINGING); // reset ringing on new channel
200
201 callinfo_orig = sccp_channel_getCallInfo(c);
202 iCallInfo.Setter(callinfo_orig, // update calling end
203 SCCP_CALLINFO_CALLEDPARTY_NAME, called_name, // channel picking up
204 SCCP_CALLINFO_CALLEDPARTY_NUMBER, called_number, SCCP_CALLINFO_ORIG_CALLEDPARTY_NAME, target_name, SCCP_CALLINFO_ORIG_CALLEDPARTY_NUMBER, target_number,
205 SCCP_CALLINFO_ORIG_CALLEDPARTY_REDIRECT_REASON, 5, SCCP_CALLINFO_LAST_REDIRECTINGPARTY_NAME, called_name, SCCP_CALLINFO_LAST_REDIRECTINGPARTY_NUMBER, called_number,
206 SCCP_CALLINFO_HUNT_PILOT_NAME, target_name, // display orig called using HUNT
207 SCCP_CALLINFO_HUNT_PILOT_NUMBER, target_number, // gets displayed as 'FOR'
208 SCCP_CALLINFO_LAST_REDIRECT_REASON, 5, SCCP_CALLINFO_KEY_SENTINEL);
209
210 // force update of hinted speeddials to Proceed
211 sccp_event_t * event = sccp_event_allocate(SCCP_EVENT_LINESTATUS_CHANGED);
212 if(event) {
213 event->lineStatusChanged.line = sccp_line_retain(c->line);
214 event->lineStatusChanged.optional_device = sccp_device_retain(d);
215 event->lineStatusChanged.state = SCCP_CHANNELSTATE_PROCEED;
216 sccp_event_fire(event);
217 }
218 sccp_log((DEBUGCAT_FEATURE))(VERBOSE_PREFIX_3 "%s: (perform_pickup) channel:%s, modeanser: %s\n", DEV_ID_LOG(d), c->designator, answer ? "yes" : "no");
219 if(answer) {
220 /* emulate previous indications, before signalling connected */
221 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_RINGIN, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
222 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_OFFHOOK, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
223 sccp_channel_answer(d, c);
224 } else {
225 /* remove previous call plane, used to dial pickup extension */
226 sccp_dev_deactivate_cplane(d);
227 sccp_parse_alertinfo(c->owner, &c->ringermode);
228 sccp_indicate(d, c, SCCP_CHANNELSTATE_RINGING);
229 sccp_dev_set_cplane(d, lineInstance, 1);
230 }
231
232 /* hangup masqueraded zombie channel*/
233 if(pbx_test_flag(pbx_channel_flags(original), AST_FLAG_ZOMBIE)) {
234 pbx_hangup(original);
235 }
236 } else { // pickup failed
237 sccp_log((DEBUGCAT_CORE))(VERBOSE_PREFIX_3 "SCCP: (perform_pickup) Giving Up\n");
238 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_TEMP_FAIL " " SKINNY_DISP_OPICKUP, SCCP_DISPLAYSTATUS_TIMEOUT);
239 c->setTone(c, SKINNY_TONE_BEEPBONK, SKINNY_TONEDIRECTION_USER);
240 sccp_channel_schedule_hangup(c, 5000);
241 }
242 #else
243 pbx_log(LOG_NOTICE, "%s: (directed_pickup) no support for pickup in asterisk\n");
244 #endif
245 return res;
246 }
247
248 /*!
249 * \brief Handle Direct Pickup of Line
250 * \param d SCCP Device
251 * \param l SCCP Line
252 * \param maybe_c Optional SCCP Channel
253 * \return SCCP Channel
254 *
255 */
sccp_feat_handle_directed_pickup(constDevicePtr d,constLinePtr l,channelPtr maybe_c)256 void sccp_feat_handle_directed_pickup(constDevicePtr d, constLinePtr l, channelPtr maybe_c)
257 {
258 #if CS_AST_DO_PICKUP
259 if (!l || !d) {
260 pbx_log(LOG_ERROR, "SCCP: Can't allocate SCCP channel if line or device are not defined!\n");
261 return;
262 }
263 AUTO_RELEASE(sccp_channel_t, c , sccp_channel_getEmptyChannel(l, d, maybe_c, SKINNY_CALLTYPE_INBOUND, NULL, NULL));
264 if(c) {
265 if(!sccp_strlen_zero(pbx_builtin_getvar_helper(c->owner, "PICKINGUP"))) {
266 pbx_log(LOG_NOTICE, "%s: (directed_pickup) pickup button has been disabled for line:%s (already pressed pickup on this call).\n", d->id, c->line->name);
267 return;
268 }
269 pbx_builtin_setvar_helper(c->owner, "PICKINGUP", "PROGRESS");
270 c->softswitch_action = SCCP_SOFTSWITCH_GETPICKUPEXTEN; /* SoftSwitch will catch a number to be dialed */
271 c->ss_data = 0; /* not needed here */
272 sccp_indicate(d, c, SCCP_CHANNELSTATE_GETDIGITS);
273 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
274 sccp_channel_stop_schedule_digittimout(c);
275 }
276 #else
277 pbx_log(LOG_NOTICE, "%s: (directed_pickup) no support for pickup in asterisk\n");
278 #endif
279 }
280
281 /*!
282 * \brief Handle Direct Pickup of Extension
283 * \param d SCCP Device
284 * \param c SCCP Channel
285 * \param lineInstance Line Instance as uint8_t
286 * \param exten Extension as char
287 * \return Success as int
288 *
289 * \lock
290 * - asterisk channel
291 */
sccp_feat_directed_pickup(constDevicePtr d,channelPtr c,uint32_t lineInstance,const char * exten)292 int sccp_feat_directed_pickup(constDevicePtr d, channelPtr c, uint32_t lineInstance, const char *exten)
293 {
294 int res = -1;
295 #if CS_AST_DO_PICKUP
296
297 /* assertions */
298 pbx_assert(c && c->line && c->owner && d);
299 if (!c->line->pickupgroup
300 #if CS_AST_HAS_NAMEDGROUP
301 && sccp_strlen_zero(c->line->namedpickupgroup)
302 #endif
303 ) {
304 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: (directedpickup) pickupgroup not configured in sccp.conf\n", d->id);
305 return -1;
306 }
307
308 char * context = NULL;
309 if (sccp_strlen_zero(exten)) {
310 pbx_log(LOG_ERROR, "SCCP: (directed_pickup) zero exten. Giving up.\n");
311 return -1;
312 }
313
314 if (!iPbx.findPickupChannelByExtenLocked) {
315 pbx_log(LOG_WARNING, "SCCP: (directed_pickup) findPickupChannelByExtenLocked not implemented for this asterisk version. Giving up.\n");
316 return -1;
317 }
318 /* end assertions */
319
320 if ((context = strchr(exten, '@'))) {
321 *context++ = '\0';
322 } else {
323 if (!sccp_strlen_zero(c->line->directed_pickup_context)) {
324 context = pbx_strdupa(c->line->directed_pickup_context);
325 } else {
326 context = pbx_strdupa(pbx_channel_context(c->owner));
327 }
328 }
329 if (sccp_strlen_zero(context)) {
330 pbx_log(LOG_ERROR, "SCCP: (directed_pickup) We could not find a context for this line. Giving up !\n");
331 return -1;
332 }
333
334 /* do pickup */
335 PBX_CHANNEL_TYPE *target = NULL; /* potential pickup target */
336 PBX_CHANNEL_TYPE *original = c->owner;
337 if (pbx_channel_ref(original)) {
338 pbx_log(LOG_NOTICE, "%s: executing directed_pickup for %s@%s\n", c->designator, exten, context);
339
340 pbx_str_t * buf = pbx_str_alloca(DEFAULT_PBX_STR_BUFFERSIZE);
341 ast_print_namedgroups(&buf, ast_channel_named_pickupgroups(original));
342 pbx_log(LOG_NOTICE, "%s: (directed_pickup) retrieving channel: %s (pickupgroup:'%lld', namedpickupgroups:'%s').\n", d->id, c->designator, ast_channel_pickupgroup(original), pbx_str_buffer(buf));
343
344 // make sure the new channel does not participate in the potential pickup candidates
345 if (iPbx.set_callgroup) {
346 iPbx.set_callgroup(c, 0);
347 }
348 if (iPbx.set_named_callgroups) {
349 iPbx.set_named_callgroups(c, NULL);
350 }
351
352 target = iPbx.findPickupChannelByExtenLocked(original, exten, context);
353 if (target) {
354 pbx_builtin_setvar_helper(c->owner, "PICKINGUP", ast_channel_name(target));
355 pbx_str_reset(buf);
356 ast_print_namedgroups(&buf, ast_channel_named_pickupgroups(target));
357 pbx_log(LOG_NOTICE, "%s: (directed_pickup) target channel found: %s (callgroup:'%lld', namedcallgroups:'%s').\n", d->id, ast_channel_name(target), ast_channel_callgroup(target), pbx_str_buffer(buf));
358 // BTW: Remote end should change it's calltype for callinfo to FORWARD, upon pickup. Not sure how to inform them
359 // iCallInfo.Send(ci, c->callid, SKINNY_CALLTYPE_FORWARD, lineInstance, d, TRUE);
360 #if ASTERISK_VERSION_GROUP > 106
361 iPbx.queue_control(target, AST_CONTROL_REDIRECTING);
362 #endif
363 sccp_device_setLamp(d, SKINNY_STIMULUS_CALLPICKUP, lineInstance, SKINNY_LAMP_FLASH);
364 res = sccp_feat_perform_pickup(d, c, target, c->line->pickup_modeanswer); /* unlocks target */
365 target = pbx_channel_unref(target);
366 sccp_device_setLamp(d, SKINNY_STIMULUS_CALLPICKUP, lineInstance, SKINNY_LAMP_OFF);
367 } else {
368 pbx_log(LOG_NOTICE, "%s: (directed_pickup) findPickupChannelByExtenLocked failed on call: %s\n", DEV_ID_LOG(d), c->designator);
369 pbx_builtin_setvar_helper(c->owner, "PICKINGUP", "FAILED");
370 sccp_dev_displayprinotify(d, SKINNY_DISP_NO_CALL_AVAILABLE_FOR_PICKUP, SCCP_MESSAGE_PRIORITY_TIMEOUT, 5);
371 if (c->state == SCCP_CHANNELSTATE_ONHOOK || c->state == SCCP_CHANNELSTATE_DOWN) {
372 sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, 0, 0, SKINNY_TONEDIRECTION_USER);
373 } else {
374 c->setTone(c, SKINNY_TONE_BEEPBONK, SKINNY_TONEDIRECTION_USER);
375 }
376 sccp_channel_schedule_hangup(c, 500);
377 }
378 pbx_channel_unref(original);
379 } else {
380 pbx_log(LOG_ERROR, "SCCP: Unable to grab a reference of the original channel owner\n");
381 }
382 #else
383 pbx_log(LOG_NOTICE, "%s: (directed_pickup) no support for pickup in asterisk\n");
384 #endif
385 return res;
386 }
387
388 /*!
389 * \brief Handle Group Pickup Feature
390 * \param d SCCP Device
391 * \param l SCCP Line
392 * \param lineInstance Line Instance as uint8_t
393 * \param maybe_c Optioonal SCCP Channel
394 * \return Success as int
395 *
396 * \todo backport from trunk
397 *
398 * \lock
399 * - asterisk channel
400 *
401 * \todo Fix callerid setting before calling ast_pickup_call
402 */
sccp_feat_grouppickup(constDevicePtr d,constLinePtr l,uint32_t lineInstance,channelPtr maybe_c)403 int sccp_feat_grouppickup(constDevicePtr d, constLinePtr l, uint32_t lineInstance, channelPtr maybe_c)
404 {
405 int res = -1;
406
407 /* assertions */
408 pbx_assert(d != NULL && l != NULL);
409 #if CS_AST_DO_PICKUP
410 if (!iPbx.findPickupChannelByGroupLocked) {
411 pbx_log(LOG_WARNING, "SCCP: (directed_pickup) findPickupChannelByExtenLocked not implemented for this asterisk version. Giving up.\n");
412 return -1;
413 }
414
415 if (!l->pickupgroup
416 #if CS_AST_HAS_NAMEDGROUP
417 && sccp_strlen_zero(l->namedpickupgroup)
418 #endif
419 ) {
420 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: (grouppickup) pickupgroup not configured in sccp.conf\n", d->id);
421 return -1;
422 }
423 /* end assertions */
424 /* re-use/create channel for pickup */
425 AUTO_RELEASE(sccp_channel_t, c , sccp_channel_getEmptyChannel(l, d, maybe_c, SKINNY_CALLTYPE_INBOUND, NULL, NULL));
426 if (c) {
427 if(!sccp_strlen_zero(pbx_builtin_getvar_helper(c->owner, "PICKINGUP"))) {
428 pbx_log(LOG_NOTICE, "%s: (directed_pickup) pickup button has been disabled for line:%s (already pressed pickup on this call).\n", d->id, l->name);
429 return -1;
430 }
431 pbx_builtin_setvar_helper(c->owner, "PICKINGUP", "PROGRESS");
432 // make sure the new channel does not participate in the potential pickup candidates
433 if (iPbx.set_callgroup) {
434 iPbx.set_callgroup(c, 0);
435 }
436 if (iPbx.set_named_callgroups) {
437 iPbx.set_named_callgroups(c, NULL);
438 }
439
440 PBX_CHANNEL_TYPE *target = NULL; /* potential pickup target */
441 PBX_CHANNEL_TYPE *original = c->owner;
442 if (pbx_channel_ref(original)) {
443 pbx_str_t * buf = pbx_str_alloca(DEFAULT_PBX_STR_BUFFERSIZE);
444 ast_print_namedgroups(&buf, ast_channel_named_pickupgroups(original));
445 pbx_log(LOG_NOTICE, "%s: (gpickup) retrieving channel: %s (%s@%s) (pickupgroup:'%lld', namedpickupgroups:'%s').\n", d->id, c->designator, pbx_channel_exten(original), pbx_channel_context(original),
446 ast_channel_pickupgroup(original), pbx_str_buffer(buf));
447 sccp_channel_stop_schedule_digittimout(c);
448 if ((target = iPbx.findPickupChannelByGroupLocked(c->owner))) {
449 pbx_builtin_setvar_helper(c->owner, "PICKINGUP", ast_channel_name(target));
450 pbx_str_reset(buf);
451 ast_print_namedgroups(&buf, ast_channel_named_pickupgroups(target));
452 pbx_log(LOG_NOTICE, "%s: (gpickup) target channel found: %s (callgroup:'%lld', namedcallgroups:'%s').\n", d->id, ast_channel_name(target), ast_channel_callgroup(target), pbx_str_buffer(buf));
453 sccp_device_setLamp(d, SKINNY_STIMULUS_GROUPCALLPICKUP, lineInstance, SKINNY_LAMP_FLASH);
454 res = sccp_feat_perform_pickup(d, c, target, l->pickup_modeanswer); /* unlocks target */
455 target = pbx_channel_unref(target);
456 sccp_device_setLamp(d, SKINNY_STIMULUS_CALLPICKUP, lineInstance, SKINNY_LAMP_OFF);
457 //res = 0;
458 } else {
459 pbx_log(LOG_NOTICE, "%s: (gpickup) findPickupChannelByExtenLocked failed on call: %s\n", DEV_ID_LOG(d), c->designator);
460 pbx_builtin_setvar_helper(c->owner, "PICKINGUP", "FAILED");
461 sccp_dev_displayprinotify(d, SKINNY_DISP_NO_CALL_AVAILABLE_FOR_PICKUP, SCCP_MESSAGE_PRIORITY_TIMEOUT, 5);
462 if (c->state == SCCP_CHANNELSTATE_ONHOOK || c->state == SCCP_CHANNELSTATE_DOWN) {
463 sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, 0, 0, SKINNY_TONEDIRECTION_USER);
464 } else {
465 c->setTone(c, SKINNY_TONE_BEEPBONK, SKINNY_TONEDIRECTION_USER);
466 }
467 sccp_channel_schedule_hangup(c, 500);
468 }
469 pbx_channel_unref(original);
470 } else {
471 pbx_log(LOG_ERROR, "SCCP: Unable to grab a reference of the original channel owner\n");
472 }
473 }
474 #else
475 pbx_log(LOG_NOTICE, "%s: (directed_pickup) no support for pickup in asterisk\n");
476 #endif
477 return res;
478 }
479 #endif // CS_SCCP_PICKUP
480
481 /*!
482 * \brief Handle VoiceMail
483 * \param d SCCP Device
484 * \param lineInstance LineInstance as uint8_t
485 *
486 */
sccp_feat_voicemail(constDevicePtr d,uint8_t lineInstance)487 void sccp_feat_voicemail(constDevicePtr d, uint8_t lineInstance)
488 {
489 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: Voicemail Button pressed on line (%d)\n", d->id, lineInstance);
490
491 {
492 AUTO_RELEASE(sccp_channel_t, c , sccp_device_getActiveChannel(d));
493
494 if (c) {
495 if (!c->line || sccp_strlen_zero(c->line->vmnum)) {
496 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: No voicemail number configured on line %d\n", d->id, lineInstance);
497 return;
498 }
499 if (c->state == SCCP_CHANNELSTATE_OFFHOOK || c->state == SCCP_CHANNELSTATE_DIALING) {
500 sccp_copy_string(c->dialedNumber, c->line->vmnum, sizeof(c->dialedNumber));
501 sccp_channel_stop_schedule_digittimout(c);
502 sccp_pbx_softswitch(c);
503 return;
504 }
505
506 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
507 return;
508 }
509 }
510
511 if (!lineInstance) {
512 if (d->defaultLineInstance) {
513 lineInstance = d->defaultLineInstance;
514 } else {
515 lineInstance = 1;
516 }
517 }
518
519 AUTO_RELEASE(sccp_line_t, l , sccp_line_find_byid(d, lineInstance));
520
521 if (!l) {
522 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: No line with instance %d found.\n", d->id, lineInstance);
523
524 // TODO(dkgroot): workaround to solve the voicemail button issue with old hint style and speeddials before first line -MC
525 if (d->defaultLineInstance) {
526 l = sccp_line_find_byid(d, d->defaultLineInstance) /*ref_replace*/;
527 }
528 }
529 if (l) {
530 if (!sccp_strlen_zero(l->vmnum)) {
531 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: Dialing voicemail %s\n", d->id, l->vmnum);
532 AUTO_RELEASE(sccp_channel_t, new_channel, sccp_channel_newcall(l, d, l->vmnum, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL)); // implicit release
533 } else {
534 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: No voicemail number configured on line %d\n", d->id, lineInstance);
535 }
536 } else {
537 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: No line with defaultLineInstance %d found. Not Dialing Voicemail Extension.\n", d->id, d->defaultLineInstance);
538 }
539 }
540
541 /*!
542 * \brief Handle Divert/Transfer Call to VoiceMail
543 * \param d SCCP Device
544 * \param l SCCP Line
545 * \param c SCCP Channel
546 */
sccp_feat_idivert(constDevicePtr d,constLinePtr l,constChannelPtr c)547 void sccp_feat_idivert(constDevicePtr d, constLinePtr l, constChannelPtr c)
548 {
549 int instance = 0;
550
551 if (!l) {
552 sccp_log((DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: TRANSVM pressed but no line found\n", d->id);
553 sccp_dev_displayprompt(d, 0, 0, SKINNY_DISP_TRANSVM_WITH_NO_LINE, SCCP_DISPLAYSTATUS_TIMEOUT);
554 return;
555 }
556 if (!l->trnsfvm) {
557 sccp_log((DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: TRANSVM pressed but not configured in sccp.conf\n", d->id);
558 return;
559 }
560 if (!c || !c->owner) {
561 sccp_log((DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: TRANSVM with no channel active\n", d->id);
562 sccp_dev_displayprompt(d, 0, 0, SKINNY_DISP_TRANSVM_WITH_NO_CHANNEL, SCCP_DISPLAYSTATUS_TIMEOUT);
563 return;
564 }
565
566 if (c->state != SCCP_CHANNELSTATE_RINGING && c->state != SCCP_CHANNELSTATE_CALLWAITING) {
567 sccp_log((DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: TRANSVM pressed in no ringing state\n", d->id);
568 return;
569 }
570
571 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: TRANSVM to %s\n", d->id, l->trnsfvm);
572 iPbx.setChannelCallForward(c, l->trnsfvm);
573 instance = sccp_device_find_index_for_line(d, l->name);
574 sccp_device_sendcallstate(d, instance, c->callid, SKINNY_CALLSTATE_PROCEED, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT); /* send connected, so it is not listed as missed call */
575 pbx_setstate(c->owner, AST_STATE_BUSY);
576 iPbx.queue_control(c->owner, AST_CONTROL_BUSY);
577 }
578
579 /*!
580 * \brief Handle 3-Way Phone Based Conferencing on a Device
581 * \param d SCCP Device
582 * \param l SCCP Line
583 * \param lineInstance lineInstance as uint8_t
584 * \param channel SCCP Channel
585 * \return SCCP Channel
586 * \todo Conferencing option needs to be build and implemented
587 * Using and External Conference Application Instead of Meetme makes it possible to use app_Conference, app_MeetMe, app_Konference and/or others
588 *
589 */
sccp_feat_handle_conference(constDevicePtr d,constLinePtr l,uint8_t lineInstance,channelPtr channel)590 void sccp_feat_handle_conference(constDevicePtr d, constLinePtr l, uint8_t lineInstance, channelPtr channel)
591 {
592 #ifdef CS_SCCP_CONFERENCE
593 if (!l || !d || sccp_strlen_zero(d->id)) {
594 pbx_log(LOG_ERROR, "SCCP: Can't allocate SCCP channel if line or device are not defined!\n");
595 return;
596 }
597
598 if (!d->allow_conference) {
599 if (lineInstance && channel && channel->callid) {
600 sccp_dev_displayprompt(d, lineInstance, channel->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
601 } else {
602 sccp_dev_displayprompt(d, 0, 0, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
603 }
604 pbx_log(LOG_NOTICE, "%s: conference not enabled\n", DEV_ID_LOG(d));
605 return;
606 }
607
608 /* if (sccp_device_numberOfChannels(d) < 2) {
609 sccp_dev_displayprompt(d, lineInstance, channel->callid, SKINNY_DISP_CAN_NOT_COMPLETE_CONFERENCE, SCCP_DISPLAYSTATUS_TIMEOUT);
610 pbx_log(LOG_NOTICE, "%s: You need at least 2 participant to start a conference\n", DEV_ID_LOG(d));
611 return;
612 }*/
613
614 AUTO_RELEASE(sccp_channel_t, c , sccp_channel_getEmptyChannel(l, d, channel, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL));
615 if (c) {
616 c->softswitch_action = SCCP_SOFTSWITCH_GETCONFERENCEROOM;
617 c->ss_data = 0; /* not needed here */
618 c->calltype = SKINNY_CALLTYPE_OUTBOUND;
619 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_OFFHOOK, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
620 sccp_channel_set_calledparty(c, "Conferencing...", "100");
621 sccp_indicate(d, c, SCCP_CHANNELSTATE_DIALING);
622 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
623 sccp_channel_stop_schedule_digittimout(c);
624 sccp_pbx_softswitch(c);
625 } else {
626 pbx_log(LOG_ERROR, "%s: (sccp_feat_handle_conference) Can't allocate SCCP channel for line %s\n", DEV_ID_LOG(d), l->name);
627 return;
628 }
629 #endif
630 }
631
632 /*!
633 * \brief Handle Conference
634 * \param device SCCP Device
635 * \param lineInstance lineInstance as uint8_t
636 * \param c SCCP Channel
637 * \return Success as int
638 * \todo Conferencing option needs to be build and implemented
639 * Using and External Conference Application Instead of Meetme makes it possible to use app_Conference, app_MeetMe, app_Konference and/or others
640 *
641 */
sccp_feat_conference_start(constDevicePtr device,const uint32_t lineInstance,channelPtr c)642 void sccp_feat_conference_start(constDevicePtr device, const uint32_t lineInstance, channelPtr c)
643 {
644 AUTO_RELEASE(sccp_device_t, d , sccp_device_retain(device));
645
646 if (!d || !c) {
647 pbx_log(LOG_NOTICE, "%s: (sccp_feat_conference_start) Missing Device or Channel\n", DEV_ID_LOG(device));
648 return;
649 }
650 #ifdef CS_SCCP_CONFERENCE
651 sccp_selectedchannel_t *selectedChannel = NULL;
652 boolean_t selectedFound = FALSE;
653 PBX_CHANNEL_TYPE *bridged_channel = NULL;
654
655 uint8_t num = sccp_device_numberOfChannels(d);
656 //int instance = sccp_device_find_index_for_line(d, l->name);
657
658 sccp_log_and((DEBUGCAT_CONFERENCE + DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: sccp_device_numberOfChannels %d.\n", DEV_ID_LOG(d), num);
659
660 if (d->conference /* && num > 3 */ ) {
661 /* if we have selected channels, add this to conference */
662
663 SCCP_LIST_LOCK(&d->selectedChannels);
664 SCCP_LIST_TRAVERSE(&d->selectedChannels, selectedChannel, list) {
665 sccp_channel_t * channel = selectedChannel->channel;
666 if (channel && channel != c) {
667 if (channel != d->active_channel && channel->state == SCCP_CHANNELSTATE_HOLD) {
668 if ((bridged_channel = iPbx.get_bridged_channel(channel->owner))) {
669 sccp_log((DEBUGCAT_CONFERENCE + DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: sccp conference: channel %s, state: %s.\n", DEV_ID_LOG(d), pbx_channel_name(bridged_channel), sccp_channelstate2str(channel->state));
670 if (!sccp_conference_addParticipatingChannel(d->conference, c, channel, bridged_channel)) {
671 sccp_dev_displayprompt(device, lineInstance, c->callid, SKINNY_DISP_INVALID_CONFERENCE_PARTICIPANT, SCCP_DISPLAYSTATUS_TIMEOUT);
672 }
673 pbx_channel_unref(bridged_channel);
674 } else {
675 pbx_log(LOG_ERROR, "%s: sccp conference: bridgedchannel for channel %s could not be found\n", DEV_ID_LOG(d), pbx_channel_name(channel->owner));
676 }
677 } else {
678 sccp_log(DEBUGCAT_CONFERENCE) (VERBOSE_PREFIX_3 "%s: sccp conference: Channel %s is Active on Shared Line on Other Device... Skipping.\n", DEV_ID_LOG(d), channel->designator);
679 }
680 selectedFound = TRUE;
681 }
682 }
683 SCCP_LIST_UNLOCK(&d->selectedChannels);
684
685 /* If no calls were selected, add all calls to the conference, across all lines. */
686 if (FALSE == selectedFound) {
687 // all channels on this phone
688 uint8_t i = 0;
689
690 for (i = 0; i < StationMaxButtonTemplateSize; i++) {
691 if (d->buttonTemplate[i].type == SKINNY_BUTTONTYPE_LINE && d->buttonTemplate[i].ptr) {
692 AUTO_RELEASE(sccp_line_t, line , sccp_line_retain(d->buttonTemplate[i].ptr));
693
694 if (line) {
695 sccp_channel_t * channel = NULL;
696 SCCP_LIST_LOCK(&line->channels);
697 SCCP_LIST_TRAVERSE(&line->channels, channel, list) {
698 if (channel != d->active_channel && channel->state == SCCP_CHANNELSTATE_HOLD) {
699 if ((bridged_channel = iPbx.get_bridged_channel(channel->owner))) {
700 sccp_log((DEBUGCAT_CONFERENCE + DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: sccp conference: channel %s, state: %s.\n", DEV_ID_LOG(d), pbx_channel_name(bridged_channel), sccp_channelstate2str(channel->state));
701 if (!sccp_conference_addParticipatingChannel(d->conference, c, channel, bridged_channel)) {
702 sccp_dev_displayprompt(device, lineInstance, c->callid, SKINNY_DISP_INVALID_CONFERENCE_PARTICIPANT, SCCP_DISPLAYSTATUS_TIMEOUT);
703 }
704 pbx_channel_unref(bridged_channel);
705 } else {
706 pbx_log(LOG_ERROR, "%s: sccp conference: bridgedchannel for channel %s could not be found\n", DEV_ID_LOG(d), pbx_channel_name(channel->owner));
707 }
708 } else {
709 sccp_log(DEBUGCAT_CONFERENCE) (VERBOSE_PREFIX_3 "%s: sccp conference: Channel %s is Active on Shared Line on Other Device...Skipping.\n", DEV_ID_LOG(d), channel->designator);
710 }
711 }
712 SCCP_LIST_UNLOCK(&line->channels);
713 }
714 }
715
716 }
717 }
718 sccp_conference_start(d->conference);
719 } else {
720 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_CAN_NOT_COMPLETE_CONFERENCE, SCCP_DISPLAYSTATUS_TIMEOUT);
721 pbx_log(LOG_NOTICE, "%s: conference could not be created\n", DEV_ID_LOG(d));
722 }
723 #else
724 sccp_log((DEBUGCAT_CONFERENCE + DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: conference not enabled\n", DEV_ID_LOG(d));
725 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
726 #endif
727 }
728
729 /*!
730 * \brief Handle Join a Conference
731 * \param device SCCP Device
732 * \param l SCCP Line
733 * \param lineInstance lineInstance as uint8_t
734 * \param c SCCP Channel
735 * \todo Conferencing option needs to be build and implemented
736 * Using and External Conference Application Instead of Meetme makes it possible to use app_Conference, app_MeetMe, app_Konference and/or others
737 */
sccp_feat_join(constDevicePtr device,constLinePtr l,uint8_t lineInstance,channelPtr c)738 void sccp_feat_join(constDevicePtr device, constLinePtr l, uint8_t lineInstance, channelPtr c)
739 {
740 AUTO_RELEASE(sccp_device_t, d , sccp_device_retain(device));
741
742 if (!c || !d) {
743 pbx_log(LOG_NOTICE, "%s: (sccp_feat_join) Missing Device or Channel\n", DEV_ID_LOG(d));
744 return;
745 }
746 #if CS_SCCP_CONFERENCE
747 AUTO_RELEASE(sccp_channel_t, newparticipant_channel , sccp_device_getActiveChannel(d));
748 sccp_channel_t *moderator_channel = NULL;
749 PBX_CHANNEL_TYPE *bridged_channel = NULL;
750
751 if (!d->allow_conference) {
752 pbx_log(LOG_NOTICE, "%s: conference not enabled\n", DEV_ID_LOG(d));
753 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_SERVICE_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
754 } else if (!d->conference) {
755 pbx_log(LOG_NOTICE, "%s: There is currently no active conference on this device. Start Conference First.\n", DEV_ID_LOG(d));
756 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_NO_CONFERENCE_BRIDGE, SCCP_DISPLAYSTATUS_TIMEOUT);
757 } else if (!newparticipant_channel) {
758 pbx_log(LOG_NOTICE, "%s: No active channel on device to join to the conference.\n", DEV_ID_LOG(d));
759 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_CAN_NOT_COMPLETE_CONFERENCE, SCCP_DISPLAYSTATUS_TIMEOUT);
760 } else if (newparticipant_channel->conference) {
761 pbx_log(LOG_NOTICE, "%s: Channel is already part of a conference.\n", DEV_ID_LOG(d));
762 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_IN_CONFERENCE_ALREADY, SCCP_DISPLAYSTATUS_TIMEOUT);
763 } else {
764 AUTO_RELEASE(sccp_conference_t, conference , sccp_conference_retain(d->conference));
765
766 SCCP_LIST_LOCK(&(((sccp_line_t *const)l)->channels));
767 SCCP_LIST_TRAVERSE(&l->channels, moderator_channel, list) {
768 if (conference == moderator_channel->conference ) {
769 break;
770 }
771 }
772 SCCP_LIST_UNLOCK(&(((sccp_line_t *const)l)->channels));
773 sccp_conference_hold(conference); // make sure conference is on hold (should already be on hold)
774 if (moderator_channel) {
775 if (newparticipant_channel && moderator_channel != newparticipant_channel) {
776 sccp_channel_hold(newparticipant_channel);
777 pbx_log(LOG_NOTICE, "%s: Joining new participant to conference\n", DEV_ID_LOG(d));
778 if ((bridged_channel = iPbx.get_bridged_channel(newparticipant_channel->owner))) {
779 sccp_log((DEBUGCAT_CONFERENCE + DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: sccp conference: channel %s, state: %s.\n", DEV_ID_LOG(d), pbx_channel_name(bridged_channel), sccp_channelstate2str(newparticipant_channel->state));
780 if (!sccp_conference_addParticipatingChannel(conference, moderator_channel, newparticipant_channel, bridged_channel)) {
781 sccp_dev_displayprompt(device, lineInstance, c->callid, SKINNY_DISP_INVALID_CONFERENCE_PARTICIPANT, SCCP_DISPLAYSTATUS_TIMEOUT);
782 }
783 pbx_channel_unref(bridged_channel);
784 } else {
785 pbx_log(LOG_ERROR, "%s: sccp conference: bridgedchannel for channel %s could not be found\n", DEV_ID_LOG(d), pbx_channel_name(newparticipant_channel->owner));
786 }
787 } else {
788 pbx_log(LOG_NOTICE, "%s: conference moderator could not be found on this phone\n", DEV_ID_LOG(d));
789 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_INVALID_CONFERENCE_PARTICIPANT, SCCP_DISPLAYSTATUS_TIMEOUT);
790 }
791 sccp_conference_update(conference);
792 sccp_channel_resume(d, moderator_channel, FALSE);
793 } else {
794 pbx_log(LOG_NOTICE, "%s: Cannot use the JOIN button within a conference itself\n", DEV_ID_LOG(d));
795 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
796 }
797 }
798 #else
799 pbx_log(LOG_NOTICE, "%s: conference not enabled\n", DEV_ID_LOG(d));
800 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_SERVICE_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
801 #endif
802 }
803
804 /*!
805 * \brief Handle Conference List
806 * \param d SCCP Device
807 * \param lineInstance lineInstance as uint8_t
808 * \param c SCCP Channel
809 * \return Success as int
810 */
sccp_feat_conflist(devicePtr d,uint8_t lineInstance,constChannelPtr c)811 void sccp_feat_conflist(devicePtr d, uint8_t lineInstance, constChannelPtr c)
812 {
813 if (d) {
814 #ifdef CS_SCCP_CONFERENCE
815 if (!d->allow_conference) {
816 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
817 pbx_log(LOG_NOTICE, "%s: conference not enabled\n", DEV_ID_LOG(d));
818 return;
819 }
820 if (c && c->conference) {
821 d->conferencelist_active = TRUE;
822 sccp_conference_show_list(c->conference, c);
823 }
824 #else
825 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
826 #endif
827 }
828 }
829
830 /*!
831 * \brief Handle 3-Way Phone Based Conferencing on a Device
832 * \param l SCCP Line
833 * \param lineInstance lineInstance as uint8_t
834 * \param d SCCP Device
835 * \return SCCP Channel
836 * \todo Conferencing option needs to be build and implemented
837 * Using and External Conference Application Instead of Meetme makes it possible to use app_Conference, app_MeetMe, app_Konference and/or others
838 *
839 */
sccp_feat_handle_meetme(constLinePtr l,uint8_t lineInstance,constDevicePtr d)840 void sccp_feat_handle_meetme(constLinePtr l, uint8_t lineInstance, constDevicePtr d)
841 {
842 if (!l || !d || sccp_strlen_zero(d->id)) {
843 pbx_log(LOG_ERROR, "SCCP: Can't allocate SCCP channel if line or device are not defined!\n");
844 return;
845 }
846
847 /* look if we have a call */
848 {
849 AUTO_RELEASE(sccp_channel_t, c , sccp_device_getActiveChannel(d));
850
851 if (c) {
852 // we have a channel, checking if
853 if (c->state == SCCP_CHANNELSTATE_OFFHOOK && sccp_strlen_zero(c->dialedNumber)) {
854 // we are dialing but without entering a number :D -FS
855 c->setTone(c, SKINNY_TONE_SILENCE, SKINNY_TONEDIRECTION_USER);
856 // changing SOFTSWITCH_DIALING mode to SOFTSWITCH_GETFORWARDEXTEN
857 c->softswitch_action = SCCP_SOFTSWITCH_GETMEETMEROOM; /* SoftSwitch will catch a number to be dialed */
858 c->ss_data = 0; /* this should be found in thread */
859 // changing channelstate to GETDIGITS
860 sccp_indicate(d, c, SCCP_CHANNELSTATE_GETDIGITS);
861 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
862 return;
863 /* there is an active call, let's put it on hold first */
864 }
865 if (!sccp_channel_hold(c)) {
866 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_TEMP_FAIL, SCCP_DISPLAYSTATUS_TIMEOUT);
867 return;
868 }
869 }
870 }
871
872 AUTO_RELEASE(sccp_channel_t, c , sccp_channel_allocate(l, d));
873
874 if (!c) {
875 pbx_log(LOG_ERROR, "%s: (handle_meetme) Can't allocate SCCP channel for line %s\n", DEV_ID_LOG(d), l->name);
876 return;
877 }
878
879 c->softswitch_action = SCCP_SOFTSWITCH_GETMEETMEROOM; /* SoftSwitch will catch a number to be dialed */
880 c->ss_data = 0; /* not needed here */
881
882 c->calltype = SKINNY_CALLTYPE_OUTBOUND;
883
884 //sccp_device_setActiveChannel(d, c);
885 sccp_indicate(d, c, SCCP_CHANNELSTATE_GETDIGITS);
886 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
887
888 /* ok the number exist. allocate the asterisk channel */
889 if(sccp_pbx_channel_allocate(c, NULL, NULL)) {
890 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
891
892 /* removing scheduled dial */
893 sccp_channel_stop_schedule_digittimout(c);
894 }
895 }
896
897 /*!
898 * \brief SCCP Meetme Application Config Structure
899 */
900 static struct meetmeAppConfig {
901 const char *appName;
902 const char *defaultMeetmeOption;
903 } meetmeApps[] = {
904 /* clang-format off */
905 {"MeetMe", "qd"},
906 {"ConfBridge", "Mac"},
907 {"Konference", "MTV"}
908 /* clang-format on */
909 };
910
911 /*!
912 * \brief a Meetme Application Thread
913 * \param data Data
914 * \author Federico Santulli
915 *
916 */
sccp_feat_meetme_thread(void * data)917 static void *sccp_feat_meetme_thread(void *data)
918 {
919 struct meetmeAppConfig *app = NULL;
920
921 char ext[SCCP_MAX_EXTENSION];
922 char context[SCCP_MAX_CONTEXT];
923
924 char meetmeopts[SCCP_MAX_CONTEXT];
925
926 #if ASTERISK_VERSION_NUMBER >= 10600
927 #define SCCP_CONF_SPACER ','
928 #endif
929
930 #if ASTERISK_VERSION_NUMBER >= 10400 && ASTERISK_VERSION_NUMBER < 10600
931 #define SCCP_CONF_SPACER '|'
932 #endif
933
934 unsigned int eid = sccp_random();
935 AUTO_RELEASE(sccp_channel_t, c , sccp_channel_retain(data));
936
937 if (!c) {
938 pbx_log(LOG_NOTICE, "SCCP: no channel provided for meetme feature. exiting\n");
939 return NULL;
940 }
941 AUTO_RELEASE(sccp_device_t, d , sccp_channel_getDevice(c));
942
943 if (!d) {
944 pbx_log(LOG_NOTICE, "SCCP: no device provided for meetme feature. exiting\n");
945 return NULL;
946 }
947 for(uint32_t i = 0; i < sizeof(meetmeApps) / sizeof(struct meetmeAppConfig); i++) {
948 if (pbx_findapp(meetmeApps[i].appName)) {
949 app = &(meetmeApps[i]);
950 sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "SCCP: using '%s' for meetme\n", meetmeApps[i].appName);
951 break;
952 }
953 }
954 /* finish searching for meetme app */
955
956 if (!app) { // \todo: remove res in this line: Although the value stored to 'res' is used in the enclosing expression, the value is never actually read from 'res'
957 pbx_log(LOG_WARNING, "SCCP: No MeetMe application available!\n");
958 //c = sccp_channel_retain(c);
959 sccp_indicate(d, c, SCCP_CHANNELSTATE_DIALING);
960 sccp_channel_set_calledparty(c, SKINNY_DISP_CONFERENCE, c->dialedNumber);
961 sccp_channel_setChannelstate(c, SCCP_CHANNELSTATE_PROCEED);
962 sccp_channel_send_callinfo(d, c);
963 sccp_indicate(d, c, SCCP_CHANNELSTATE_INVALIDCONFERENCE);
964 return NULL;
965 }
966 // SKINNY_DISP_CAN_NOT_COMPLETE_CONFERENCE
967 if (c && c->owner) {
968 if (c->pbx_callid) {
969 pbx_callid_threadassoc_add(c->pbx_callid);
970 }
971 if (!pbx_channel_context(c->owner) || sccp_strlen_zero(pbx_channel_context(c->owner))) {
972 return NULL;
973 }
974 if (!sccp_strlen_zero(c->line->meetmeopts)) {
975 snprintf(meetmeopts, sizeof(meetmeopts), "%s%c%s", c->dialedNumber, SCCP_CONF_SPACER, c->line->meetmeopts);
976 } else if (!sccp_strlen_zero(d->meetmeopts)) {
977 snprintf(meetmeopts, sizeof(meetmeopts), "%s%c%s", c->dialedNumber, SCCP_CONF_SPACER, d->meetmeopts);
978 } else if (!sccp_strlen_zero(GLOB(meetmeopts))) {
979 snprintf(meetmeopts, sizeof(meetmeopts), "%s%c%s", c->dialedNumber, SCCP_CONF_SPACER, GLOB(meetmeopts));
980 } else {
981 snprintf(meetmeopts, sizeof(meetmeopts), "%s%c%s", c->dialedNumber, SCCP_CONF_SPACER, app->defaultMeetmeOption);
982 }
983
984 sccp_copy_string(context, pbx_channel_context(c->owner), sizeof(context));
985
986 snprintf(ext, sizeof(ext), "sccp_meetme_temp_conference_%ud", eid);
987
988 if (!pbx_exists_extension(NULL, context, ext, 1, NULL)) {
989 pbx_add_extension(context, 1, ext, 1, NULL, NULL, app->appName, meetmeopts, NULL, "sccp_feat_meetme_thread");
990 pbx_log(LOG_WARNING, "SCCP: create extension exten => %s,%d,%s(%s)\n", ext, 1, app->appName, meetmeopts);
991 }
992 // sccp_copy_string(c->owner->exten, ext, sizeof(c->owner->exten));
993 iPbx.setChannelExten(c, ext);
994
995 if(sccp_channel_retain(c)) { // explicit retain
996 sccp_indicate(d, c, SCCP_CHANNELSTATE_DIALING);
997 sccp_channel_set_calledparty(c, SKINNY_DISP_CONFERENCE, c->dialedNumber);
998 // sccp_channel_setSkinnyCallstate(c, SKINNY_CALLSTATE_PROCEED);
999 sccp_channel_setChannelstate(c, SCCP_CHANNELSTATE_PROCEED);
1000 sccp_channel_send_callinfo(d, c);
1001 sccp_indicate(d, c, SCCP_CHANNELSTATE_CONNECTED);
1002
1003 if(pbx_pbx_run(c->owner)) {
1004 sccp_indicate(d, c, SCCP_CHANNELSTATE_INVALIDCONFERENCE);
1005 pbx_log(LOG_WARNING, "SCCP: SCCP_CHANNELSTATE_INVALIDCONFERENCE\n");
1006 }
1007 ast_context_remove_extension(context, ext, 1, NULL);
1008 }
1009 if (c->pbx_callid) {
1010 pbx_callid_threadassoc_remove();
1011 }
1012 }
1013 return NULL;
1014 }
1015
1016 /*!
1017 * \brief Start a Meetme Application Thread
1018 * \param c SCCP Channel
1019 * \author Federico Santulli
1020 */
sccp_feat_meetme_start(channelPtr c)1021 void sccp_feat_meetme_start(channelPtr c)
1022 {
1023 sccp_threadpool_add_work(GLOB(general_threadpool), sccp_feat_meetme_thread, (void *) c);
1024 }
1025
1026 #define BASE_REGISTRAR "chan_sccp"
1027
1028 typedef struct sccp_barge_info_t {
1029 PBX_CONTEXT_TYPE *context;
1030 sccp_channel_t *bargedChannel;
1031 sccp_channel_t *bargingChannel;
1032 } sccp_barge_info_t;
1033
cleanupTempExtensionContext(void * ptr)1034 static void *cleanupTempExtensionContext(void *ptr)
1035 {
1036 sccp_barge_info_t *barge_info= (struct sccp_barge_info_t *)ptr;
1037 sccp_channel_t *bdc = barge_info->bargedChannel;
1038 sccp_channel_t *bgc = barge_info->bargingChannel;
1039
1040 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "SCCP: destroy temp context:%p\n", barge_info->context);
1041 pbx_context_destroy(barge_info->context, BASE_REGISTRAR);
1042
1043 // restore previous barged channel state
1044 bgc->isBarging = FALSE;
1045 if (bdc) {
1046 bdc->isBarged = FALSE;
1047 bdc->channelStateReason = SCCP_CHANNELSTATEREASON_NORMAL;
1048 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "%s: Reindicate CONNECTED to re-set remote-indication\n", bdc->designator);
1049 bdc->state = bdc->previousChannelState;
1050 sccp_indicate(NULL, bdc, SCCP_CHANNELSTATE_CONNECTED);
1051 sccp_channel_release(&barge_info->bargedChannel);
1052 }
1053
1054 sccp_channel_release(&barge_info->bargingChannel);
1055 sccp_free(barge_info);
1056 return 0;
1057 }
1058
createTempExtensionContext(channelPtr c,const char * context_name,const char * ext,const char * app,const char * opts)1059 static sccp_barge_info_t * createTempExtensionContext(channelPtr c, const char *context_name, const char *ext, const char *app, const char *opts)
1060 {
1061 if (c) {
1062 sccp_barge_info_t *barge_info = (sccp_barge_info_t *) sccp_calloc(1, sizeof(sccp_barge_info_t));
1063 if (barge_info) {
1064 if ((barge_info->context = pbx_context_find_or_create(NULL, NULL, context_name, BASE_REGISTRAR))) {
1065 barge_info->bargingChannel = sccp_channel_retain(c);
1066 pbx_add_extension(context_name, /*replace*/1, ext, /*prio*/1, /*label*/NULL, /*cidmatch*/NULL, "Answer", NULL, NULL, BASE_REGISTRAR);
1067 pbx_add_extension(context_name, /*replace*/1, ext, /*prio*/2, /*label*/NULL, /*cidmatch*/NULL, app, pbx_strdup(opts), sccp_free_ptr, BASE_REGISTRAR);
1068 pbx_add_extension(context_name, /*replace*/1, ext, /*prio*/3, /*label*/NULL, /*cidmatch*/NULL, "Hangup", NULL, NULL, BASE_REGISTRAR);
1069 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "SCCP: created temp context:%s and extension:%s to call %s, with options:'%s'\n", context_name, ext, app, opts);
1070 sccp_channel_addCleanupJob(c, &cleanupTempExtensionContext, barge_info);
1071 return barge_info;
1072 }
1073 sccp_free(barge_info);
1074 }
1075 }
1076 return NULL;
1077 }
1078
1079 /*!
1080 * \brief Handle Barging into a Call
1081 * \param l SCCP Line
1082 * \param lineInstance lineInstance as uint8_t
1083 * \param d SCCP Device
1084 * \return SCCP Channel
1085 *
1086 */
sccp_feat_handle_barge(constLinePtr l,uint8_t lineInstance,constDevicePtr d,channelPtr maybe_c)1087 void sccp_feat_handle_barge(constLinePtr l, uint8_t lineInstance, constDevicePtr d, channelPtr maybe_c)
1088 {
1089
1090 if (!l || !d || sccp_strlen_zero(d->id)) {
1091 pbx_log(LOG_ERROR, "SCCP: Can't allocate SCCP channel if line or device are not defined!\n");
1092 return;
1093 }
1094 if (maybe_c) {
1095 AUTO_RELEASE(sccp_device_t, remoted, maybe_c->getDevice(maybe_c));
1096 if (l->isShared && d != remoted) { // we are peering at a remote shared line
1097 /* use the channel pointed to on the screen */
1098 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "%s: handling barge on shared line\n", maybe_c->designator);
1099 AUTO_RELEASE(sccp_channel_t, bargedChannel, sccp_channel_retain(maybe_c));
1100 AUTO_RELEASE(sccp_linedevice_t, bargingLineDevice, sccp_linedevice_find(d, l));
1101 if (!sccp_feat_sharedline_barge(bargingLineDevice, bargedChannel)) {
1102 sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, lineInstance, 0, SKINNY_TONEDIRECTION_USER);
1103 }
1104 return;
1105 }
1106 // fall through
1107 }
1108 AUTO_RELEASE(sccp_channel_t, c, sccp_channel_getEmptyChannel(l, d, maybe_c, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL));
1109 if (c) {
1110 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "%s: handling barge on single line:%s\n", d->id, l->name);
1111 c->softswitch_action = SCCP_SOFTSWITCH_GETBARGEEXTEN; /* SoftSwitch will catch a number to be dialed */
1112 c->ss_data = 0; /* not needed here */
1113 sccp_indicate(d, c, SCCP_CHANNELSTATE_GETDIGITS);
1114 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
1115 sccp_channel_stop_schedule_digittimout(c);
1116 if (!maybe_c) {
1117 sccp_pbx_softswitch(c);
1118 }
1119 } else {
1120 pbx_log(LOG_ERROR, "%s: (sccp_feat_handle_barge) Can't allocate SCCP channel for line %s\n", DEV_ID_LOG(d), l->name);
1121 sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_FAILED_TO_SETUP_BARGE, SCCP_DISPLAYSTATUS_TIMEOUT);
1122 sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, lineInstance, 0, SKINNY_TONEDIRECTION_USER);
1123 }
1124 }
1125
1126 /*!
1127 * \brief Barging into a Call Feature
1128 * \param c SCCP Channel
1129 * \param exten Extention as char
1130 * \return Success as int
1131 */
sccp_feat_singleline_barge(channelPtr c,const char * const exten)1132 int sccp_feat_singleline_barge(channelPtr c, const char * const exten)
1133 {
1134 if (!c) {
1135 pbx_log(LOG_ERROR, "SCCP: (sccp_feat_sharedline_barge) called without valid channel\n");
1136 return FALSE;
1137 }
1138 AUTO_RELEASE(sccp_linedevice_t, bargingLD, sccp_channel_getLineDevice(c));
1139 sccp_barge_info_t *barge_info = NULL;
1140
1141 if(!bargingLD) {
1142 pbx_log(LOG_ERROR, "SCCP: (sccp_feat_sharedline_barge) called without bargingLD\n");
1143 return FALSE;
1144 }
1145 if (!bargingLD->line) {
1146 pbx_log(LOG_ERROR, "SCCP: (sccp_feat_sharedline_barge) called without valid bargingLD->line\n");
1147 sccp_dev_displayprompt(bargingLD->device, bargingLD->lineInstance, 0, SKINNY_DISP_FAILED_TO_SETUP_BARGE, SCCP_DISPLAYSTATUS_TIMEOUT);
1148 sccp_dev_starttone(bargingLD->device, SKINNY_TONE_BEEPBONK, bargingLD->lineInstance, 0, SKINNY_TONEDIRECTION_USER);
1149 return FALSE;
1150 }
1151 sccp_device_t *d = bargingLD->device;
1152 AUTO_RELEASE(sccp_line_t, l, sccp_line_retain(bargingLD->line));
1153 uint16_t lineInstance = bargingLD->lineInstance;
1154
1155 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "%s: is barging in on:%s\n", c->designator, /*pbx_channel_name(pbxchannel)*/exten);
1156 char ext[SCCP_MAX_EXTENSION];
1157 char context[SCCP_MAX_CONTEXT];
1158 char opts[SCCP_MAX_CONTEXT];
1159
1160 // check privacy on ast channel
1161 // check already barged on ast channel
1162 //bargedChannel->isBarged = TRUE;
1163 // retrieve list of channeltypes
1164
1165 snprintf(context, sizeof(context), "sccp_barge_%s_%s", d->id, l->name);
1166 snprintf(ext, sizeof(ext), "%s", l->cid_num);
1167 //snprintf(opts, sizeof(opts), "%s@%s,%c%s", exten, l->context, SCCP_CONF_SPACER, "bBE");
1168 snprintf(opts, sizeof(opts), "SCCP/%s:SIP/%s:IAX2/%s%c%s", exten, exten, exten, SCCP_CONF_SPACER, "sbBE");
1169 if ((barge_info = createTempExtensionContext(c, context, ext, "ExtenSpy", opts))) {
1170 // setup softswitch
1171 c->softswitch_action = SCCP_SOFTSWITCH_DIAL;
1172 c->ss_data = 0;
1173
1174 // channel switch newly create context
1175 iPbx.setChannelContext(c, context);
1176 sccp_copy_string(c->dialedNumber, ext, sizeof(c->dialedNumber));
1177
1178 // set channel to correct mode
1179 c->isBarging = TRUE;
1180 sccp_channel_setDevice(c, d, TRUE);
1181 sccp_indicate(d, c, SCCP_CHANNELSTATE_OFFHOOK);
1182 c->channelStateReason = SCCP_CHANNELSTATEREASON_BARGE;
1183 sccp_channel_setChannelstate(c, SCCP_CHANNELSTATE_PROCEED);
1184
1185 // update caller info
1186 //sccp_channel_set_calledparty(c, "barged", !sccp_strlen_zero(bargedChannel->subscriptionId.name) ? bargedChannel->subscriptionId.name : bargedChannel->subscriptionId.number);
1187 sccp_channel_set_callingparty(c, "barger", !sccp_strlen_zero(c->subscriptionId.name) ? c->subscriptionId.name : c->subscriptionId.number);
1188
1189 // execute softswitch
1190 sccp_pbx_softswitch(c);
1191
1192 // display prompt on Barged Device
1193 /*
1194 barge_info->bargedChannel = sccp_channel_retain(bargedChannel);
1195 barge_info->bargedChannel->isBarged = TRUE;
1196 AUTO_RELEASE(sccp_channel_t,bargedChannel, CS_AST_CHANNEL_PVT(pbxchannel) ? sccp_channel_retain(CS_AST_CHANNEL_PVT(pbxchannel)) : NULL);
1197 if (bargedChannel) {
1198 char statusmsg[40];
1199 AUTO_RELEASE(sccp_linedevices_t, bargedLineDevice, bargedChannel->getLineDevice(bargedChannel));
1200 if (!bargedLineDevice || !bargedLineDevice->device) {
1201 snprintf(statusmsg, sizeof(statusmsg), SKINNY_DISP_BARGE " " SKINNY_DISP_FROM " %s", l->cid_num);
1202 sccp_dev_displayprompt(bargedLineDevice->device, bargedLineDevice->lineInstance, bargedChannel->callid, statusmsg, SCCP_DISPLAYSTATUS_TIMEOUT);
1203 }
1204 }
1205 */
1206 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "%s: is barged in on:%s\n", c->designator, /*pbx_channel_name(pbxchannel)*/ exten);
1207 } else {
1208 pbx_log(LOG_ERROR, "Failed to automatically find or create "
1209 "context '%s' for sccp_barge!\n", context);
1210 sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_FAILED_TO_SETUP_BARGE, SCCP_DISPLAYSTATUS_TIMEOUT);
1211 return FALSE;
1212 }
1213 return TRUE;
1214 }
1215
1216 /*!
1217 * \brief Barging into a Call Feature
1218 * \param c SCCP Channel
1219 * \param exten Extention as char
1220 * \return Success as int
1221 */
sccp_feat_sharedline_barge(constLineDevicePtr bargingLD,channelPtr bargedChannel)1222 int sccp_feat_sharedline_barge(constLineDevicePtr bargingLD, channelPtr bargedChannel)
1223 {
1224 if (!bargingLD) {
1225 pbx_log(LOG_ERROR, "SCCP: (sccp_feat_sharedline_barge) called without bargingLD\n");
1226 return FALSE;
1227 }
1228 if (!bargingLD->line || !bargedChannel) {
1229 pbx_log(LOG_ERROR, "SCCP: (sccp_feat_sharedline_barge) called without valid bargingLD->line or bargedChannel\n");
1230 sccp_dev_displayprompt(bargingLD->device, bargingLD->lineInstance, 0, SKINNY_DISP_FAILED_TO_SETUP_BARGE, SCCP_DISPLAYSTATUS_TIMEOUT);
1231 return FALSE;
1232 }
1233 sccp_device_t *d = bargingLD->device;
1234 AUTO_RELEASE(sccp_line_t, l, sccp_line_retain(bargingLD->line));
1235 sccp_barge_info_t *barge_info = NULL;
1236 uint16_t lineInstance = bargingLD->lineInstance;
1237
1238 // check privacy status of destination
1239 if (bargedChannel->privacy) {
1240 sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_PRIVATE, SCCP_DISPLAYSTATUS_TIMEOUT);
1241 return FALSE;
1242 }
1243 if (bargedChannel->isBarged) {
1244 sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_ANOTHER_BARGE_EXISTS, SCCP_DISPLAYSTATUS_TIMEOUT);
1245 return FALSE;
1246 }
1247 bargedChannel->isBarged = TRUE;
1248
1249 AUTO_RELEASE(sccp_linedevice_t, bargedLineDevice, bargedChannel->getLineDevice(bargedChannel));
1250 if (!bargedLineDevice || !bargedLineDevice->device) {
1251 sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_FAILED_TO_SETUP_BARGE, SCCP_DISPLAYSTATUS_TIMEOUT);
1252 return FALSE;
1253 }
1254
1255 AUTO_RELEASE(sccp_channel_t, c , sccp_channel_getEmptyChannel(l, d, NULL, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL));
1256 if (c) {
1257 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "%s: is barging in on:%s\n", c->designator, bargedChannel->designator);
1258 char ext[SCCP_MAX_EXTENSION];
1259 char context[SCCP_MAX_CONTEXT];
1260 char opts[SCCP_MAX_CONTEXT];
1261 char statusmsg[40];
1262
1263 snprintf(context, sizeof(context), "sccp_barge_%s_%s", d->id, l->name);
1264 snprintf(ext, sizeof(ext), "%s", l->cid_num);
1265 snprintf(opts, sizeof(opts), "SCCP/%s%c%s", bargedChannel->line->name, SCCP_CONF_SPACER, "qbBE");
1266 if ((barge_info = createTempExtensionContext(c, context, ext, "ChanSpy", opts))) {
1267 // setup softswitch
1268 c->softswitch_action = SCCP_SOFTSWITCH_DIAL;
1269 c->ss_data = 0;
1270
1271 // channel switch newly create context
1272 iPbx.setChannelContext(c, context);
1273 sccp_copy_string(c->dialedNumber, ext, sizeof(c->dialedNumber));
1274
1275 // set channel to correct mode
1276 c->isBarging = TRUE;
1277 sccp_channel_setDevice(c, d, TRUE);
1278 barge_info->bargedChannel = sccp_channel_retain(bargedChannel);
1279 sccp_indicate(d, c, SCCP_CHANNELSTATE_OFFHOOK);
1280 c->channelStateReason = SCCP_CHANNELSTATEREASON_BARGE;
1281 sccp_channel_setChannelstate(c, SCCP_CHANNELSTATE_PROCEED);
1282
1283 // update caller info
1284 sccp_channel_set_calledparty(c, "barged", !sccp_strlen_zero(bargedChannel->subscriptionId.name) ? bargedChannel->subscriptionId.name : bargedChannel->subscriptionId.number);
1285 sccp_channel_set_callingparty(c, "barger", !sccp_strlen_zero(c->subscriptionId.name) ? c->subscriptionId.name : c->subscriptionId.number);
1286
1287 // execute softswitch
1288 sccp_pbx_softswitch(c);
1289
1290 pbx_builtin_setvar_helper(c->owner, "BARGED", bargedChannel->designator);
1291 pbx_builtin_setvar_helper(bargedChannel->owner, "BARGED_BY", c->designator);
1292
1293 // hide the channel we barged into
1294 d->indicate->remoteConnected(d, lineInstance, bargedChannel->callid, SKINNY_CALLINFO_VISIBILITY_HIDDEN);
1295
1296 // display prompt on Barged Device
1297 snprintf(statusmsg, sizeof(statusmsg), SKINNY_DISP_BARGE " " SKINNY_DISP_FROM " %s", l->cid_num);
1298 sccp_dev_set_message(d, statusmsg, SCCP_DISPLAYSTATUS_TIMEOUT, FALSE, FALSE);
1299 bargedChannel->setTone(bargedChannel, SKINNY_TONE_ZIP, SKINNY_TONEDIRECTION_BOTH);
1300
1301 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_2 "%s: is barged in on:%s\n", c->designator, bargedChannel->designator);
1302 } else {
1303 pbx_log(LOG_ERROR, "Failed to automatically find or create "
1304 "context '%s' for sccp_barge!\n", context);
1305 sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_FAILED_TO_SETUP_BARGE, SCCP_DISPLAYSTATUS_TIMEOUT);
1306 return FALSE;
1307 }
1308 }
1309 return TRUE;
1310 }
1311
1312 /*!
1313 * \brief Handle Barging into a Conference
1314 * \param l SCCP Line
1315 * \param lineInstance lineInstance as uint8_t
1316 * \param d SCCP Device
1317 * \return SCCP Channel
1318 * \todo Conferencing option needs to be build and implemented
1319 * Using and External Conference Application Instead of Meetme makes it possible to use app_Conference, app_MeetMe, app_Konference and/or others
1320 *
1321 */
sccp_feat_handle_cbarge(constLinePtr l,uint8_t lineInstance,constDevicePtr d)1322 void sccp_feat_handle_cbarge(constLinePtr l, uint8_t lineInstance, constDevicePtr d)
1323 {
1324
1325 if (!l || !d || sccp_strlen(d->id) < 3) {
1326 pbx_log(LOG_ERROR, "SCCP: Can't allocate SCCP channel if line or device are not defined!\n");
1327 return;
1328 }
1329
1330 /* look if we have a call */
1331 {
1332 AUTO_RELEASE(sccp_channel_t, c , sccp_device_getActiveChannel(d));
1333
1334 if (c) {
1335 // we have a channel, checking if
1336 if (c->state == SCCP_CHANNELSTATE_OFFHOOK && sccp_strlen_zero(c->dialedNumber)) {
1337 // we are dialing but without entering a number :D -FS
1338 c->setTone(c, SKINNY_TONE_SILENCE, SKINNY_TONEDIRECTION_USER);
1339 // changing SOFTSWITCH_DIALING mode to SOFTSWITCH_GETFORWARDEXTEN
1340 c->softswitch_action = SCCP_SOFTSWITCH_GETBARGEEXTEN; /* SoftSwitch will catch a number to be dialed */
1341 c->ss_data = 0; /* this should be found in thread */
1342 // changing channelstate to GETDIGITS
1343 sccp_indicate(d, c, SCCP_CHANNELSTATE_GETDIGITS);
1344 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
1345 return;
1346 } if (!sccp_channel_hold(c)) {
1347 /* there is an active call, let's put it on hold first */
1348 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_TEMP_FAIL, SCCP_DISPLAYSTATUS_TIMEOUT);
1349 return;
1350 }
1351 }
1352 }
1353
1354 AUTO_RELEASE(sccp_channel_t, c , sccp_channel_allocate(l, d));
1355
1356 if (!c) {
1357 pbx_log(LOG_ERROR, "%s: (handle_cbarge) Can't allocate SCCP channel for line %s\n", d->id, l->name);
1358 return;
1359 }
1360
1361 c->softswitch_action = SCCP_SOFTSWITCH_GETCBARGEROOM; /* SoftSwitch will catch a number to be dialed */
1362 c->ss_data = 0; /* not needed here */
1363
1364 c->calltype = SKINNY_CALLTYPE_OUTBOUND;
1365
1366 //sccp_device_setActiveChannel(d, c);
1367 sccp_indicate(d, c, SCCP_CHANNELSTATE_GETDIGITS);
1368 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
1369
1370 /* ok the number exist. allocate the asterisk channel */
1371 if(sccp_pbx_channel_allocate(c, NULL, NULL)) {
1372 iPbx.set_callstate(c, AST_STATE_OFFHOOK);
1373 }
1374 }
1375
1376 /*!
1377 * \brief Barging into a Conference Feature
1378 * \param c SCCP Channel
1379 * \param conferencenum Conference Number as char
1380 * \return Success as int
1381 */
sccp_feat_cbarge(constChannelPtr c,const char * const conferencenum)1382 int sccp_feat_cbarge(constChannelPtr c, const char * const conferencenum)
1383 {
1384 /* sorry but this is private code -FS */
1385 if (!c) {
1386 return -1;
1387 }
1388 AUTO_RELEASE(sccp_device_t, d , sccp_channel_getDevice(c));
1389
1390 if (!d) {
1391 return -1;
1392 }
1393 uint8_t instance = sccp_device_find_index_for_line(d, c->line->name);
1394
1395 sccp_dev_displayprompt(d, instance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
1396 return 1;
1397 }
1398
1399 /*!
1400 * \brief Hotline Feature
1401 *
1402 * Setting the hotline Feature on a device, will make it connect to a predefined extension as soon as the Receiver
1403 * is picked up or the "New Call" Button is pressed. No number has to be given.
1404 *
1405 * \param d SCCP Device
1406 * \param line SCCP Line
1407 */
sccp_feat_adhocDial(constDevicePtr d,constLinePtr line)1408 void sccp_feat_adhocDial(constDevicePtr d, constLinePtr line)
1409 {
1410 if (!d || !d->session || !line) {
1411 return;
1412 }
1413 sccp_log((DEBUGCAT_FEATURE + DEBUGCAT_LINE)) (VERBOSE_PREFIX_3 "%s: handling hotline\n", d->id);
1414
1415 AUTO_RELEASE(sccp_channel_t, c , sccp_device_getActiveChannel(d));
1416
1417 if (c) {
1418 if ((c->state == SCCP_CHANNELSTATE_DIALING) || (c->state == SCCP_CHANNELSTATE_OFFHOOK)) {
1419 sccp_copy_string(c->dialedNumber, line->adhocNumber, sizeof(c->dialedNumber));
1420 sccp_channel_stop_schedule_digittimout(c);
1421
1422 sccp_pbx_softswitch(c);
1423 return;
1424 }
1425 //sccp_pbx_senddigits(c, line->adhocNumber);
1426 if (iPbx.send_digits) {
1427 iPbx.send_digits(c, line->adhocNumber);
1428 }
1429 } else {
1430 // Pull up a channel
1431 if (GLOB(hotline)->line) {
1432 AUTO_RELEASE(sccp_channel_t, new_channel, sccp_channel_newcall(line, d, line->adhocNumber, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL)); // explicit release
1433 }
1434 }
1435 }
1436
1437 /*!
1438 * \brief Handler to Notify Features have Changed
1439 * \param device SCCP Device
1440 * \param ld SCCP LineDevice
1441 * \param featureType SCCP Feature Type
1442 *
1443 */
sccp_feat_changed(constDevicePtr device,constLineDevicePtr maybe_ld,sccp_feature_type_t featureType)1444 void sccp_feat_changed(constDevicePtr device, constLineDevicePtr maybe_ld, sccp_feature_type_t featureType)
1445 {
1446 if (device) {
1447 sccp_featButton_changed(device, featureType);
1448 sccp_event_t *event = sccp_event_allocate(SCCP_EVENT_FEATURE_CHANGED);
1449 if (event) {
1450 event->featureChanged.device = sccp_device_retain(device);
1451 event->featureChanged.optional_linedevice = maybe_ld ? sccp_linedevice_retain(maybe_ld) : NULL;
1452 event->featureChanged.featureType = featureType;
1453 sccp_event_fire(event);
1454 }
1455 sccp_log(DEBUGCAT_FEATURE)(VERBOSE_PREFIX_3 "%s: Feature %s Change Event Scheduled\n", device->id, sccp_feature_type2str(featureType));
1456 }
1457 }
1458
1459 /*!
1460 * \brief Switch Monitor Feature on/off
1461 *
1462 * \note: iPbx.feature_monitor will ask asterisk to start/stop automon
1463 * \note: asterisk ami events are evaluated and callback via sccp_asterisk_managerHookHelper upon change, which
1464 * will in turn call sccp_feat_changed to update the monitor state (if such a state change happens)
1465 * \see: sccp_management.c for more information
1466 */
sccp_feat_monitor(constDevicePtr device,constLinePtr no_line,uint32_t no_lineInstance,constChannelPtr maybe_channel)1467 void sccp_feat_monitor(constDevicePtr device, constLinePtr no_line, uint32_t no_lineInstance, constChannelPtr maybe_channel)
1468 {
1469 sccp_featureConfiguration_t *monitorFeature = (sccp_featureConfiguration_t *const)&device->monitorFeature; /* discard const */
1470 if (!maybe_channel) {
1471 if (monitorFeature->status & SCCP_FEATURE_MONITOR_STATE_REQUESTED) {
1472 monitorFeature->status &= ~SCCP_FEATURE_MONITOR_STATE_REQUESTED;
1473 } else {
1474 monitorFeature->status |= SCCP_FEATURE_MONITOR_STATE_REQUESTED;
1475 }
1476 } else {
1477 constChannelPtr channel = maybe_channel;
1478 pbx_str_t *amiCommandStr = pbx_str_alloca(DEFAULT_PBX_STR_BUFFERSIZE);
1479 char * outStr = NULL;
1480 if (!(monitorFeature->status & SCCP_FEATURE_MONITOR_STATE_ACTIVE)) {
1481 pbx_str_append(&amiCommandStr,0 ,"Action: Monitor\r\n");
1482 pbx_str_append(&amiCommandStr,0 ,"Channel: %s\r\n", pbx_channel_name(channel->owner));
1483 pbx_str_append(&amiCommandStr,0 ,"File: mixmonitor-%s-%d_%s.wav\r\n", channel->line->name, channel->callid, iPbx.getChannelUniqueID(channel));
1484 pbx_str_append(&amiCommandStr,0 ,"Format: wav\r\n");
1485 pbx_str_append(&amiCommandStr,0 ,"Mix: true\r\n");
1486 pbx_str_append(&amiCommandStr,0 ,"\r\n");
1487 //monitorFeature->status &= ~SCCP_FEATURE_MONITOR_STATE_ACTIVE; /* no need to change status, will be done by sccp_asterisk_managerHookHelper */
1488 } else {
1489 pbx_str_append(&amiCommandStr,0 ,"Action: StopMonitor\r\n");
1490 pbx_str_append(&amiCommandStr,0 ,"Channel: %s\r\n", pbx_channel_name(channel->owner));
1491 pbx_str_append(&amiCommandStr,0 ,"\r\n");
1492 //monitorFeature->status |= SCCP_FEATURE_MONITOR_STATE_ACTIVE;
1493 }
1494 if (sccp_manager_action2str(pbx_str_buffer(amiCommandStr), &outStr) && outStr) {
1495 if (
1496 sccp_strequals(outStr, "Response: Success\r\nMessage: Started monitoring channel\r\n\r\n") ||
1497 sccp_strequals(outStr, "Response: Success\r\nMessage: Stopped monitoring channel\r\n\r\n")
1498 ) {
1499 sccp_log((DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: (sccp_feat_monitor) AMI monitor request sent successfully.\n", DEV_ID_LOG(device));
1500 // sccp_asterisk_managerHookHelper will catch the result and update the softkey / featureButton accordingly.
1501 } else {
1502 sccp_dev_displayprinotify(device, SKINNY_DISP_RECORDING_FAILED, SCCP_MESSAGE_PRIORITY_MONITOR, SCCP_DISPLAYSTATUS_TIMEOUT*3);
1503 pbx_log(LOG_ERROR, "%s: (sccp_feat_monitor) AMI monitor request failed.\n", DEV_ID_LOG(device));
1504 monitorFeature->status = SCCP_FEATURE_MONITOR_STATE_DISABLED;
1505 }
1506 sccp_free(outStr);
1507 } else {
1508 pbx_log(LOG_ERROR, "%s: (sccp_feat_monitor) AMI monitor request failed.\n", DEV_ID_LOG(device));
1509 monitorFeature->status = SCCP_FEATURE_MONITOR_STATE_DISABLED;
1510 }
1511 }
1512 sccp_log((DEBUGCAT_FEATURE)) (VERBOSE_PREFIX_3 "%s: (sccp_feat_monitor) new monitor status:%s (%d)\n", device->id, sccp_feature_monitor_state2str(monitorFeature->status), monitorFeature->status);
1513 }
1514 // kate: indent-width 8; replace-tabs off; indent-mode cstyle; auto-insert-doxygen on; line-numbers on; tab-indents on; keep-extra-spaces off; auto-brackets off;
1515