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