1 /*!
2  * \file        sccp_softkeys.c
3  * \brief       SCCP SoftKeys Class
4  * \author      Sergio Chersovani <mlists [at] c-net.it>
5  * \note        Reworked, but based on chan_sccp code.
6  *              The original chan_sccp driver that was made by Zozo which itself was derived from the chan_skinny driver.
7  *              Modified by Jan Czmok and Julien Goodwin
8  * \note        This program is free software and may be modified and distributed under the terms of the GNU Public License.
9  *              See the LICENSE file at the top of the source tree.
10  *
11  */
12 
13 #include "config.h"
14 #include "common.h"
15 #include "sccp_pbx.h"
16 #include "sccp_channel.h"
17 #include "sccp_softkeys.h"
18 #include "sccp_actions.h"
19 #include "sccp_device.h"
20 #include "sccp_feature.h"
21 #include "sccp_line.h"
22 #include "sccp_linedevice.h"
23 #include "sccp_session.h"
24 #include "sccp_utils.h"
25 #include "sccp_labels.h"
26 
27 SCCP_FILE_VERSION(__FILE__, "");
28 
29 const uint8_t softkeysmap[32] = {
30 	SKINNY_LBL_REDIAL,
31 	SKINNY_LBL_NEWCALL,
32 	SKINNY_LBL_HOLD,
33 	SKINNY_LBL_TRANSFER,
34 	SKINNY_LBL_CFWDALL,
35 	SKINNY_LBL_CFWDBUSY,
36 	SKINNY_LBL_CFWDNOANSWER,
37 	SKINNY_LBL_BACKSPACE,
38 	SKINNY_LBL_ENDCALL,
39 	SKINNY_LBL_RESUME,
40 	SKINNY_LBL_ANSWER,
41 	SKINNY_LBL_INFO,
42 	SKINNY_LBL_CONFRN,
43 	SKINNY_LBL_PARK,
44 	SKINNY_LBL_JOIN,
45 	SKINNY_LBL_MEETME,
46 	SKINNY_LBL_PICKUP,
47 	SKINNY_LBL_GPICKUP,
48 	SKINNY_LBL_MONITOR,
49 	SKINNY_LBL_CALLBACK,
50 	SKINNY_LBL_BARGE,
51 	SKINNY_LBL_DND,
52 	SKINNY_LBL_CONFLIST,
53 	SKINNY_LBL_SELECT,
54 	SKINNY_LBL_PRIVATE,
55 	SKINNY_LBL_TRNSFVM,
56 	SKINNY_LBL_DIRTRFR,
57 	SKINNY_LBL_IDIVERT,
58 	SKINNY_LBL_VIDEO_MODE,
59 	SKINNY_LBL_INTRCPT,
60 	SKINNY_LBL_EMPTY,
61 	SKINNY_LBL_DIAL,
62 	//SKINNY_LBL_CBARGE,
63 };														/*!< SKINNY Soft Keys Map as INT */
64 
65 
66 /* =========================================================================================== Global */
67 /*!
68  * \brief Global list of softkeys
69  */
70 struct softKeySetConfigList softKeySetConfig;									/*!< List of SoftKeySets */
71 
72 /*!
73  * \brief SCCP SoftKeyMap Callback
74  *
75  * Used to Map Softkeys to there Handling Implementation
76  */
77 struct sccp_softkeyMap_cb {
78 	uint32_t event;
79 	boolean_t channelIsNecessary;
80 	void (*softkeyEvent_cb) (const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c);
81 	char *uriactionstr;
82 };
83 
84 /* =========================================================================================== Private */
85 /*
86  * \brief Helper to find the correct line to use
87  * \returns retained line
88  */
sccp_sk_get_retained_line(constDevicePtr d,constLinePtr l,const uint32_t lineInstance,constChannelPtr c,char * error_str)89 static const sccp_line_t * sccp_sk_get_retained_line(constDevicePtr d, constLinePtr l, const uint32_t lineInstance, constChannelPtr c, char *error_str) {
90 	const sccp_line_t *line = NULL;
91 	if (l && (line = sccp_line_retain(l))) {
92 		return line;
93 	}
94 	if (c && c->line && (line = sccp_line_retain(c->line))) {
95 		return line;
96 	}
97 	if (d && lineInstance && (line = sccp_line_find_byid(d, lineInstance))) {
98 		return line;
99 	}
100 	if (d && d->currentLine && (line = sccp_dev_getActiveLine(d))) {
101 		return line;
102 	}
103 	if (d && d->defaultLineInstance > 0 && (line = sccp_line_find_byid(d, d->defaultLineInstance))) {
104 		return line;
105 	}
106 	sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: No line found\n", DEV_ID_LOG(d));
107 	if(c) {
108 		c->setTone(c, SKINNY_TONE_ZIPZIP, SKINNY_TONEDIRECTION_USER);
109 	} else {
110 		sccp_dev_starttone(d, SKINNY_TONE_ZIPZIP, lineInstance, 0, SKINNY_TONEDIRECTION_USER);
111 	}
112 	sccp_dev_displayprompt(d, lineInstance, 0, error_str, SCCP_DISPLAYSTATUS_TIMEOUT);
113 	return NULL;
114 }
115 
116 /*!
117  * \brief Forces Dialling before timeout
118  */
sccp_sk_dial(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)119 static void sccp_sk_dial(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
120 {
121 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Dial Pressed\n", DEV_ID_LOG(d));
122 	if (c && !iPbx.getChannelPbx(c)) {									// Prevent dialling if in an inappropriate state.
123 		/* Only handle this in DIALING state. AFAIK GETDIGITS is used only for call forward and related input functions. (-DD) */
124 		if (c->state == SCCP_CHANNELSTATE_DIGITSFOLL || c->softswitch_action == SCCP_SOFTSWITCH_GETFORWARDEXTEN) {
125 			sccp_pbx_softswitch(c);
126 		}
127 	}
128 }
129 
130 /*!
131  * \brief Start/Stop VideoMode
132  *
133  * \todo Add doxygen entry for sccp_sk_videomode
134  * \todo Implement stopping video transmission
135  */
sccp_sk_videomode(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)136 static void sccp_sk_videomode(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
137 {
138 #ifdef CS_SCCP_VIDEO
139 	if (sccp_device_isVideoSupported(d) && c->preferences.video[0] != SKINNY_CODEC_NONE) {
140 		sccp_log((DEBUGCAT_RTP)) (VERBOSE_PREFIX_3 "%s: We can have video, try to start vrtp\n", DEV_ID_LOG(d));
141 		if(!c->rtp.video.instance || sccp_rtp_getState(&c->rtp.video, SCCP_RTP_RECEPTION)) {
142 			sccp_channel_openMultiMediaReceiveChannel(c);
143 		}
144 		if((sccp_rtp_getState(&c->rtp.video, SCCP_RTP_RECEPTION) & SCCP_RTP_STATUS_ACTIVE) && !sccp_rtp_getState(&c->rtp.video, SCCP_RTP_TRANSMISSION)) {
145 			sccp_channel_startMultiMediaTransmission(c);
146 		}
147 		sccp_channel_setVideoMode(c, "user");
148 	}
149 #endif
150 }
151 
152 /*!
153  * \brief Redial last Dialed Number by this Device
154  */
sccp_sk_redial(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)155 static void sccp_sk_redial(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
156 {
157 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Redial Pressed\n", DEV_ID_LOG(d));
158 	if (!d) {
159 		return;
160 	}
161 	char * data = NULL;
162 
163 	if (d->useRedialMenu) {
164 		if (d->protocol->type == SCCP_PROTOCOL) {
165 			if (d->protocolversion < 15) {
166 				data = "<CiscoIPPhoneExecute><ExecuteItem Priority=\"0\" URL=\"Key:Directories\"/><ExecuteItem Priority=\"0\" URL=\"Key:KeyPad3\"/></CiscoIPPhoneExecute>";
167 			} else {
168 				data = "<CiscoIPPhoneExecute><ExecuteItem Priority=\"0\" URL=\"Application:Cisco/PlacedCalls\"/></CiscoIPPhoneExecute>";
169 			}
170 		} else {
171 			data = "<CiscoIPPhoneExecute><ExecuteItem Priority=\"0\" URL=\"Key:Setup\"/><ExecuteItem Priority=\"0\" URL=\"Key:KeyPad1\"/><ExecuteItem Priority=\"0\" URL=\"Key:KeyPad3\"/></CiscoIPPhoneExecute>";
172 			//data = "<CiscoIPPhoneExecute><ExecuteItem Priority=\"0\" URL=\"Application:Cisco/PlacedCalls\"/></CiscoIPPhoneExecute>";
173 		}
174 
175 		d->protocol->sendUserToDeviceDataVersionMessage(d, 0, lineInstance, 0, 0, data, 0);
176 		return;
177 	}
178 
179 	if (sccp_strlen_zero(d->redialInformation.number)) {
180 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: No number to redial\n", d->id);
181 		return;
182 	}
183 
184 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: Get ready to redial number %s lineInstance: %d\n", d->id, d->redialInformation.number, d->redialInformation.lineInstance ? d->redialInformation.lineInstance : lineInstance);
185 	if (c) {
186 		if (c->state == SCCP_CHANNELSTATE_OFFHOOK) {
187 			/* we have a offhook channel */
188 			sccp_copy_string(c->dialedNumber, d->redialInformation.number, sizeof(c->dialedNumber));
189 			sccp_pbx_softswitch(c);
190 		}
191 		/* here's a KEYMODE error. nothing to do */
192 		return;
193 	}
194 	AUTO_RELEASE(const sccp_line_t, line,
195 		     d->redialInformation.lineInstance == 0 ? sccp_line_find_byid(d, d->redialInformation.lineInstance) : sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
196 	if(!line) {
197 		line = sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE) /*ref_replace*/;
198 	}
199 	if (line) {
200 		AUTO_RELEASE(sccp_channel_t, new_channel, sccp_channel_newcall(line, d, d->redialInformation.number, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL));
201 		/* implicit release */
202 	} else {
203 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: Redial pressed on a device without a registered line\n", d->id);
204 	}
205 }
206 
207 /*!
208  * \brief Initiate a New Call
209  */
sccp_sk_newcall(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)210 static void sccp_sk_newcall(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
211 {
212 	char *adhocNumber = NULL;
213 	sccp_speed_t k;
214 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
215 	if (!line) {
216 		return;
217 	}
218 
219 	uint8_t instance = sccp_device_find_index_for_line(d, line->name);
220 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey NewCall Pressed\n", DEV_ID_LOG(d));
221 
222 	if (!line || instance != lineInstance) {
223 		/* handle dummy speeddial */
224 		sccp_dev_speed_find_byindex(d, lineInstance, TRUE, &k);
225 		if (sccp_strlen(k.ext) > 0) {
226 			adhocNumber = pbx_strdupa(k.ext);
227 		}
228 	}
229 	if (!adhocNumber && !sccp_strlen_zero(line->adhocNumber)) {
230 		adhocNumber = pbx_strdupa(line->adhocNumber);
231 	}
232 
233 	/* check if we have an active channel on an other line, that does not have any dialed number
234 	 * (Can't select line after already off-hook - https://sourceforge.net/p/chan-sccp-b/discussion/652060/thread/878fe455/?limit=25#c06e/6006/a54d)
235 	 */
236 	if(!adhocNumber) {
237 		AUTO_RELEASE(sccp_channel_t, activeChannel, sccp_device_getActiveChannel(d));
238 		if(activeChannel && activeChannel->line != l && sccp_strlen(activeChannel->dialedNumber) == 0) {
239 			sccp_channel_endcall(activeChannel);
240 		}
241 	}
242 	/* done */
243 
244 	AUTO_RELEASE(sccp_channel_t, new_channel, sccp_channel_newcall(line, d, adhocNumber, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL)); /* implicit release */
245 }
246 
247 /*!
248  * \brief Hold Call on Current Line
249  */
sccp_sk_hold(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)250 static void sccp_sk_hold(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
251 {
252 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Hold Pressed\n", DEV_ID_LOG(d));
253 	if (!c) {
254 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: No call to put on hold, check your softkeyset, hold should not be available in this situation.\n", DEV_ID_LOG(d));
255 		sccp_dev_displayprompt(d, 0, 0, SKINNY_DISP_NO_ACTIVE_CALL_TO_PUT_ON_HOLD, SCCP_DISPLAYSTATUS_TIMEOUT);
256 		return;
257 	}
258 	sccp_channel_hold(c);
259 }
260 
261 /*!
262  * \brief Resume Call on Current Line
263  */
sccp_sk_resume(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)264 static void sccp_sk_resume(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
265 {
266 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Resume Pressed\n", DEV_ID_LOG(d));
267 	if (!c) {
268 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: No call to resume. Ignoring\n", d->id);
269 		return;
270 	}
271 	sccp_channel_resume(d, c, TRUE);
272 }
273 
274 /*!
275  * \brief Transfer Call on Current Line
276  *
277  * \todo discus Marcello's transfer experiment
278  */
sccp_sk_transfer(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)279 static void sccp_sk_transfer(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
280 {
281 	sccp_channel_transfer(c, d);
282 }
283 
284 /*!
285  * \brief End Call on Current Line
286  */
sccp_sk_endcall(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)287 static void sccp_sk_endcall(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
288 {
289 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey EndCall Pressed\n", DEV_ID_LOG(d));
290 	if (!c) {
291 		pbx_log(LOG_NOTICE, "%s: Endcall with no call in progress\n", d->id);
292 		return;
293 	}
294 
295 	if (c->calltype == SKINNY_CALLTYPE_INBOUND && 1 < c->subscribers--) {					// && pbx_channel_state(c->owner) != AST_STATE_UP) {
296 		if (d && d->indicate && d->indicate->onhook) {
297 			d->indicate->onhook(d, lineInstance, c->callid);
298 		}
299 	} else {
300 		sccp_channel_endcall(c);
301 	}
302 
303 #if 0														/* new */
304 	if (!(c->calltype == SKINNY_CALLTYPE_INBOUND && 1 < c->subscribers--)) {
305 		sccp_channel_endcall(c);
306 	}
307 	if (d && d->indicate && d->indicate->onhook) {
308 		d->indicate->onhook(d, lineInstance, c->callid);
309 	}
310 #endif
311 }
312 
313 /*!
314  * \brief Set DND on Current Line if Line is Active otherwise set on Device
315  *
316  * \todo The line param is not used
317  */
sccp_sk_dnd(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)318 static void sccp_sk_dnd(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
319 {
320 	if (!d) {
321 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "SCCP: sccp_sk_dnd function called without specifying a device\n");
322 		return;
323 	}
324 
325 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey DND Pressed (Current Status: %s, Feature enabled: %s)\n", DEV_ID_LOG(d), sccp_dndmode2str((sccp_dndmode_t)d->dndFeature.status), d->dndFeature.enabled ? "YES" : "NO");
326 
327 	if (!d->dndFeature.enabled) {
328 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: SoftKey DND Feature disabled\n", DEV_ID_LOG(d));
329 		sccp_dev_displayprompt(d, lineInstance, c ? c->callid : 0, SKINNY_DISP_DND " " SKINNY_DISP_SERVICE_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
330 		sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, 0, 0, SKINNY_TONEDIRECTION_USER);
331 		return;
332 	}
333 
334 	//AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
335 	AUTO_RELEASE(const sccp_line_t, line, l ? sccp_line_retain(l) : NULL);
336 	AUTO_RELEASE(sccp_device_t, device, sccp_device_retain(d));
337 	if (device) {
338 		do {
339 			// check line/device dnd config flag, if found skip rest
340 			if (line) {
341 				if (line->dndmode == SCCP_DNDMODE_REJECT) {					// line config is set to: dnd=reject
342 					if (device->dndFeature.status == SCCP_DNDMODE_OFF) {
343 						device->dndFeature.status = SCCP_DNDMODE_REJECT;
344 					} else {
345 						device->dndFeature.status = SCCP_DNDMODE_OFF;
346 					}
347 					break;
348 				} else if (line->dndmode == SCCP_DNDMODE_SILENT) {				// line config is set to: dnd=silent
349 					if (device->dndFeature.status == SCCP_DNDMODE_OFF) {
350 						device->dndFeature.status = SCCP_DNDMODE_SILENT;
351 					} else {
352 						device->dndFeature.status = SCCP_DNDMODE_OFF;
353 					}
354 					break;
355 				}
356 			} else {
357 				if (device->dndmode == SCCP_DNDMODE_REJECT) {					// device config is set to: dnd=reject
358 					if (device->dndFeature.status == SCCP_DNDMODE_OFF) {
359 						device->dndFeature.status = SCCP_DNDMODE_REJECT;
360 					} else {
361 						device->dndFeature.status = SCCP_DNDMODE_OFF;
362 					}
363 					break;
364 				} else if (device->dndmode == SCCP_DNDMODE_SILENT) {				// device config is set to: dnd=silent
365 					if (device->dndFeature.status == SCCP_DNDMODE_OFF) {
366 						device->dndFeature.status = SCCP_DNDMODE_SILENT;
367 					} else {
368 						device->dndFeature.status = SCCP_DNDMODE_OFF;
369 					}
370 					break;
371 				}
372 			}
373 			// for all other config use the toggle mode
374 			switch (device->dndFeature.status) {
375 				case SCCP_DNDMODE_OFF:
376 					device->dndFeature.status = SCCP_DNDMODE_REJECT;
377 					break;
378 				case SCCP_DNDMODE_REJECT:
379 					device->dndFeature.status = SCCP_DNDMODE_SILENT;
380 					break;
381 				case SCCP_DNDMODE_SILENT:
382 					/* fall through */
383 				default:
384 					device->dndFeature.status = SCCP_DNDMODE_OFF;
385 					break;
386 			}
387 			sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey DND Pressed (New Status: %s, Feature enabled: %s)\n", DEV_ID_LOG(d), sccp_dndmode2str((sccp_dndmode_t)device->dndFeature.status), device->dndFeature.enabled ? "YES" : "NO");
388 		} while (0);
389 
390 		sccp_feat_changed(device, NULL, SCCP_FEATURE_DND);							// notify the modules the the DND-feature changed state
391 		sccp_dev_check_displayprompt(device);									//! \todo we should use the feature changed event to check displayprompt
392 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey DND Pressed (New Status: %s, Feature enabled: %s)\n", DEV_ID_LOG(device), sccp_dndmode2str((sccp_dndmode_t)device->dndFeature.status), device->dndFeature.enabled ? "YES" : "NO");
393 	}
394 
395 }
396 
397 /*!
398  * \brief BackSpace Last Entered Number
399  */
sccp_sk_backspace(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)400 static void sccp_sk_backspace(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
401 {
402 	if (!d) {
403 		return;
404 	}
405 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Backspace Pressed\n", DEV_ID_LOG(d));
406 
407 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
408 	if (!line) {
409 		return;
410 	}
411 	int len = 0;
412 
413 	if (((c->state != SCCP_CHANNELSTATE_DIALING) && (c->state != SCCP_CHANNELSTATE_DIGITSFOLL) && (c->state != SCCP_CHANNELSTATE_OFFHOOK) && (c->state != SCCP_CHANNELSTATE_GETDIGITS)) || iPbx.getChannelPbx(c)) {
414 		return;
415 	}
416 
417 	len = sccp_strlen(c->dialedNumber);
418 
419 	/* we have no number, so nothing to process */
420 	if (!len) {
421 		sccp_channel_schedule_digittimeout(c, GLOB(firstdigittimeout));
422 		return;
423 	}
424 
425 	if (len >= 1) {
426 		c->dialedNumber[len - 1] = '\0';
427 		sccp_channel_schedule_digittimeout(c, GLOB(digittimeout));
428 	}
429 	// sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: backspacing dial number %s\n", c->device->id, c->dialedNumber);
430 	sccp_handle_dialtone(d, line, c);
431 	sccp_handle_backspace(d, lineInstance, c->callid);
432 }
433 
434 /*!
435  * \brief Answer Incoming Call
436  */
sccp_sk_answer(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)437 static void sccp_sk_answer(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
438 {
439 	if (!c) {
440 		char buf[100];
441 		ast_log(LOG_WARNING, "%s: (sccp_sk_answer) Pressed the answer key without any channel%s%s\n", d->id, l ? " on line: " : "", l ? l->name : "");
442 		snprintf(buf, 100, SKINNY_DISP_NO_CHANNEL_TO_PERFORM_XXXXXXX_ON " " SKINNY_GIVING_UP, "ANSWER");
443 		sccp_dev_displayprinotify(d, buf, SCCP_MESSAGE_PRIORITY_TIMEOUT, 5);
444 		sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, lineInstance, 0, SKINNY_TONEDIRECTION_USER);
445 		return;
446 	}
447 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Answer Pressed, instance: %d\n", DEV_ID_LOG(d), lineInstance);
448 
449 	/* taking the reference during a locked ast channel allows us to call sccp_channel_answer unlock without the risk of loosing the channel */
450 	if (c->owner) {
451 		sccp_channel_answer(d, c);
452 	}
453 }
454 
455 /*!
456  * \brief Bridge two selected channels
457  */
sccp_sk_dirtrfr(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)458 static void sccp_sk_dirtrfr(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
459 {
460 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Direct Transfer Pressed\n", DEV_ID_LOG(d));
461 
462 	AUTO_RELEASE(sccp_device_t, device , sccp_device_retain(d));
463 
464 	if (!device) {
465 		return;
466 	}
467 
468 	AUTO_RELEASE(sccp_channel_t, chan1, NULL);
469 	AUTO_RELEASE(sccp_channel_t, chan2, NULL);
470 	if ((sccp_device_selectedchannels_count(device)) == 2) {
471 		sccp_selectedchannel_t *x = NULL;
472 		SCCP_LIST_LOCK(&device->selectedChannels);
473 		if((x = SCCP_LIST_FIRST(&device->selectedChannels))) {
474 			chan1 = sccp_channel_retain(x->channel) /*ref_replace*/;
475 			sccp_channel_t * tmp = NULL;
476 			if((tmp = SCCP_LIST_NEXT(x, list)->channel)) {
477 				chan2 = sccp_channel_retain(tmp) /*ref_replace*/;
478 			}
479 		}
480 		SCCP_LIST_UNLOCK(&device->selectedChannels);
481 	} else {
482 		AUTO_RELEASE(sccp_line_t, line , sccp_line_retain(l));
483 		if (line) {
484 			if (SCCP_RWLIST_GETSIZE(&line->channels) == 2) {
485 				SCCP_LIST_LOCK(&line->channels);
486 				sccp_channel_t *tmp = NULL;
487 				if ((tmp  = SCCP_LIST_FIRST(&line->channels))) {
488 					chan1 = sccp_channel_retain(tmp) /*ref_replace*/;
489 					if ((tmp = SCCP_LIST_NEXT(tmp, list))) {
490 						chan2 = sccp_channel_retain(tmp) /*ref_replace*/;
491 					}
492 				}
493 				SCCP_LIST_UNLOCK(&line->channels);
494 			} else if (SCCP_RWLIST_GETSIZE(&line->channels) < 2) {
495 				sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: Not enough channels to transfer\n", device->id);
496 				sccp_dev_displayprompt(device, lineInstance, c->callid, SKINNY_DISP_NOT_ENOUGH_CALLS_TO_TRANSFER, SCCP_DISPLAYSTATUS_TIMEOUT);
497 				return;
498 			} else {
499 				sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: More than 2 channels to transfer, please use softkey select\n", device->id);
500 				sccp_dev_displayprompt(device, lineInstance, c->callid, SKINNY_DISP_MORE_THAN_TWO_CALLS ", " SKINNY_DISP_USE " " SKINNY_DISP_SELECT, SCCP_DISPLAYSTATUS_TIMEOUT);
501 				return;
502 			}
503 		}
504 	}
505 
506 
507 	if (chan1 && chan2) {
508 		//for using the sccp_channel_transfer_complete function
509 		//chan2 must be in RINGOUT or CONNECTED state
510 		sccp_dev_displayprompt(device, lineInstance, c->callid, SKINNY_DISP_CALL_TRANSFER, SCCP_DISPLAYSTATUS_TIMEOUT);
511 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: (sccp_sk_dirtrfr) First Channel Status (%d), Second Channel Status (%d)\n", DEV_ID_LOG(device), chan1->state, chan2->state);
512 		if (chan2->state != SCCP_CHANNELSTATE_CONNECTED && chan1->state == SCCP_CHANNELSTATE_CONNECTED) {
513 			/* reverse channels */
514 			sccp_channel_t * tmp = chan1;
515 			chan1 = chan2 /*ref_replace*/;
516 			chan2 = tmp /*ref_replace*/;
517 		} else if (chan1->state == SCCP_CHANNELSTATE_HOLD && chan2->state == SCCP_CHANNELSTATE_HOLD) {
518 			//resume chan2 if both channels are on hold
519 			sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: (sccp_sk_dirtrfr) Resuming Second Channel (%d)\n", DEV_ID_LOG(device), chan2->state);
520 			sccp_channel_resume(device, chan2, TRUE);
521 			sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: (sccp_sk_dirtrfr) Resumed Second Channel (%d)\n", DEV_ID_LOG(device), chan2->state);
522 		}
523 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: (sccp_sk_dirtrfr) First Channel Status (%d), Second Channel Status (%d)\n", DEV_ID_LOG(device), chan1->state, chan2->state);
524 		device->transferChannels.transferee = sccp_channel_retain(chan1);
525 		device->transferChannels.transferer = sccp_channel_retain(chan2);
526 		if (device->transferChannels.transferee && device->transferChannels.transferer) {
527 			sccp_channel_transfer_complete(chan2);
528 		}
529 	}
530 }
531 
532 /*!
533  * \brief Select a Line for further processing by for example DirTrfr
534  */
sccp_sk_select(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)535 static void sccp_sk_select(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
536 {
537 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Select Pressed\n", DEV_ID_LOG(d));
538 	sccp_selectedchannel_t * selectedchannel = NULL;
539 	sccp_msg_t * msg = NULL;
540 	uint8_t numSelectedChannels = 0;
541 
542 	uint8_t status = 0;
543 
544 	if (!d) {
545 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "SCCP: (sccp_sk_select) Can't select a channel without a device\n");
546 		return;
547 	}
548 	if (!c) {
549 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: (sccp_sk_select) No channel to be selected\n", DEV_ID_LOG(d));
550 		return;
551 	}
552 
553 	AUTO_RELEASE(sccp_device_t, device , sccp_device_retain(d));
554 	if (device) {
555 		if ((selectedchannel = sccp_device_find_selectedchannel(device, c))) {
556 			SCCP_LIST_LOCK(&device->selectedChannels);
557 			selectedchannel = SCCP_LIST_REMOVE(&device->selectedChannels, selectedchannel, list);
558 			SCCP_LIST_UNLOCK(&device->selectedChannels);
559 			sccp_channel_release(&selectedchannel->channel);
560 			sccp_free(selectedchannel);
561 		} else {
562 			selectedchannel = (sccp_selectedchannel_t *) sccp_calloc(sizeof *selectedchannel, 1);
563 			if (selectedchannel != NULL) {
564 				selectedchannel->channel = sccp_channel_retain(c);
565 				SCCP_LIST_LOCK(&device->selectedChannels);
566 				SCCP_LIST_INSERT_HEAD(&device->selectedChannels, selectedchannel, list);
567 				SCCP_LIST_UNLOCK(&device->selectedChannels);
568 				status = 1;
569 			} else {
570 				pbx_log(LOG_ERROR, SS_Memory_Allocation_Error, "SCCP");
571 				return;
572 			}
573 		}
574 		numSelectedChannels = sccp_device_selectedchannels_count(device);
575 
576 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: (sccp_sk_select) '%d' channels selected\n", DEV_ID_LOG(device), numSelectedChannels);
577 
578 		REQ(msg, CallSelectStatMessage);
579 		msg->data.CallSelectStatMessage.lel_status = htolel(status);
580 		msg->data.CallSelectStatMessage.lel_lineInstance = htolel(lineInstance);
581 		msg->data.CallSelectStatMessage.lel_callReference = htolel(c->callid);
582 		sccp_dev_send(d, msg);
583 	}
584 }
585 
586 /*!
587  * \brief Set Call Forward All on Current Line
588  */
sccp_sk_cfwdall(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)589 static void sccp_sk_cfwdall(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
590 {
591 	if (!d) {
592 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "SCCP: sccp_sk_cfwdall function called without specifying a device\n");
593 		return;
594 	}
595 
596 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
597 
598 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Call Forward All Pressed, line: %s, instance: %d, channel: %d\n", DEV_ID_LOG(d), l ? l->name : "(NULL)", lineInstance, c ? c->callid : 0);
599 
600 	if (line && d->cfwdall) {
601 		sccp_feat_handle_callforward(line, d, SCCP_CFWD_ALL, c, lineInstance);
602 		return;
603 	}
604 	sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: CFWDALL disabled on device\n", d->id);
605 	sccp_dev_displayprompt(d, 0, 0, SKINNY_DISP_CFWDALL " " SKINNY_DISP_SERVICE_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
606 	sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, 0, 0, SKINNY_TONEDIRECTION_USER);
607 
608 }
609 
610 /*!
611  * \brief Set Call Forward when Busy on Current Line
612  */
sccp_sk_cfwdbusy(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)613 static void sccp_sk_cfwdbusy(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
614 {
615 	if (!d) {
616 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "SCCP: sccp_sk_cfwdbusy function called without specifying a device\n");
617 		return;
618 	}
619 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
620 
621 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Call Forward Busy Pressed\n", DEV_ID_LOG(d));
622 	if (line && d->cfwdbusy) {
623 		sccp_feat_handle_callforward(line, d, SCCP_CFWD_BUSY, c, lineInstance);
624 		return;
625 	}
626 	sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: CFWDBUSY disabled on device\n", d->id);
627 	sccp_dev_displayprompt(d, 0, 0, SKINNY_DISP_CFWDBUSY " " SKINNY_DISP_SERVICE_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
628 	sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, 0, 0, SKINNY_TONEDIRECTION_USER);
629 }
630 
631 /*!
632  * \brief Set Call Forward when No Answer on Current Line
633  */
sccp_sk_cfwdnoanswer(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)634 static void sccp_sk_cfwdnoanswer(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
635 {
636 	if (!d) {
637 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "SCCP: sccp_sk_cfwdnoanswer function called without specifying a device\n");
638 		return;
639 	}
640 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
641 
642 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Call Forward NoAnswer Pressed\n", DEV_ID_LOG(d));
643 	if (line && d->cfwdnoanswer) {
644 		sccp_feat_handle_callforward(line, d, SCCP_CFWD_NOANSWER, c, lineInstance);
645 		return;
646 	}
647 	sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: CFWDNoAnswer disabled on device\n", d->id);
648 	sccp_dev_displayprompt(d, 0, 0, SKINNY_DISP_CFWDNOANSWER " " SKINNY_DISP_SERVICE_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
649 	sccp_dev_starttone(d, SKINNY_TONE_BEEPBONK, 0, 0, SKINNY_TONEDIRECTION_USER);
650 }
651 
652 /*!
653  * \brief Park Call on Current Line
654  */
sccp_sk_park(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)655 static void sccp_sk_park(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
656 {
657 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Park Pressed\n", DEV_ID_LOG(d));
658 #ifdef CS_SCCP_PARK
659 	sccp_channel_park(c);
660 #else
661 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Native park was not compiled in\n");
662 #endif
663 }
664 
665 /*!
666  * \brief Transfer to VoiceMail on Current Line
667  */
sccp_sk_trnsfvm(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)668 static void sccp_sk_trnsfvm(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
669 {
670 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
671 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Transfer Voicemail Pressed\n", DEV_ID_LOG(d));
672 	if (line) {
673 		sccp_feat_idivert(d, line, c);
674 	}
675 }
676 
677 /*!
678  * \brief Initiate Private Call on Current Line
679  *
680  */
sccp_sk_private(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr device,constLinePtr l,const uint32_t lineInstance,channelPtr c)681 static void sccp_sk_private(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr device, constLinePtr l, const uint32_t lineInstance, channelPtr c)
682 {
683 	if(!device) {
684 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "SCCP: sccp_sk_private function called without specifying a device\n");
685 		return;
686 	}
687 	AUTO_RELEASE(sccp_device_t, d, sccp_device_retain(device));
688 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Private Pressed\n", DEV_ID_LOG(d));
689 
690 	if (!d->privacyFeature.enabled) {
691 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: private function is not active on this device\n", d->id);
692 		sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_PRIVATE_FEATURE_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
693 		return;
694 	}
695 
696 	uint8_t instance = 0;
697 	AUTO_RELEASE(sccp_channel_t, channel, c ? sccp_channel_retain(c) : NULL);
698 	if(channel) {
699 		instance = lineInstance;
700 	} else {
701 		AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_PRIVATE_WITHOUT_LINE_CHANNEL));
702 		sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: Creating new PRIVATE channel\n", d->id);
703 		if(line) {
704 			instance = sccp_device_find_index_for_line(d, line->name);
705 			sccp_dev_setActiveLine(d, line);
706 			sccp_dev_set_cplane(d, instance, 1);
707 			channel = sccp_channel_newcall(line, d, NULL, SKINNY_CALLTYPE_OUTBOUND, NULL, NULL) /*ref_replace*/;
708 		}
709 	}
710 
711 	if (!channel) {
712 		sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_PRIVATE_WITHOUT_LINE_CHANNEL, SCCP_DISPLAYSTATUS_TIMEOUT);
713 		return;
714 	}
715 	// check device->privacyFeature.status before toggeling
716 
717 	// toggle
718 	channel->privacy = !channel->privacy;
719 	sccp_softkey_setSoftkeyState(d, KEYMODE_ONHOOKSTEALABLE, SKINNY_LBL_BARGE, channel->privacy);
720 
721 	// update device->privacyFeature.status  using sccp_feat_changed
722 	//sccp_feat_changed(d, NULL, SCCP_FEATURE_PRIVACY);
723 
724 	// Should actually use the messageStack instead of using displayprompt directly
725 	if (channel->privacy) {
726 		sccp_channel_set_calleridPresentation(channel, CALLERID_PRESENTATION_FORBIDDEN);
727 		pbx_builtin_setvar_helper(channel->owner, "SKINNY_PRIVATE", "1");
728 		sccp_device_addMessageToStack(d, SCCP_MESSAGE_PRIORITY_PRIVACY, SKINNY_DISP_PRIVATE);
729 		sccp_dev_displayprompt(d, instance, channel->callid, SKINNY_DISP_PRIVATE, 5);
730 	} else {
731 		pbx_builtin_setvar_helper(channel->owner, "SKINNY_PRIVATE", "0");
732 		sccp_channel_set_calleridPresentation(c, CALLERID_PRESENTATION_ALLOWED);
733 		sccp_device_clearMessageFromStack(d, SCCP_MESSAGE_PRIORITY_PRIVACY);
734 	}
735 	sccp_log((DEBUGCAT_CORE)) (VERBOSE_PREFIX_3 "%s: Private %s on call %d\n", d->id, channel->privacy ? "enabled" : "disabled", channel->callid);
736 }
737 
738 /*!
739  * \brief Monitor Current Line
740  */
sccp_sk_monitor(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)741 static void sccp_sk_monitor(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
742 {
743 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
744 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Monitor Pressed\n", DEV_ID_LOG(d));
745 	if (line) {
746 		sccp_feat_monitor(d, line, lineInstance, c);
747 	}
748 }
749 
750 /*!
751  * \brief Put Current Line into Conference
752  * \todo Conferencing option needs to be build and implemented
753  *       Using and External Conference Application Instead of Meetme makes it possible to use app_Conference, app_MeetMe, app_Konference and/or others
754  */
sccp_sk_conference(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)755 static void sccp_sk_conference(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
756 {
757 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Conference Pressed\n", DEV_ID_LOG(d));
758 #ifdef CS_SCCP_CONFERENCE
759 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
760 	if (line) {
761 		sccp_feat_handle_conference(d, line, lineInstance, c);
762 	}
763 #else
764 	sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
765 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Conference was not compiled in\n");
766 #endif
767 }
768 
769 /*!
770  * \brief Show Participant List of Current Conference
771  * \todo Conferencing option is under development.
772  */
sccp_sk_conflist(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)773 static void sccp_sk_conflist(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
774 {
775 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Conflist Pressed\n", DEV_ID_LOG(d));
776 #ifdef CS_SCCP_CONFERENCE
777 	AUTO_RELEASE(sccp_device_t, device , sccp_device_retain(d));
778 	if (device) {
779 		sccp_feat_conflist(device, lineInstance, c);
780 	}
781 #else
782 	sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
783 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Conference was not compiled in\n");
784 #endif
785 }
786 
787 /*!
788  * \brief Join Current Line to Conference
789  * \todo Conferencing option needs to be build and implemented
790  */
sccp_sk_join(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)791 static void sccp_sk_join(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
792 {
793 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Join Pressed\n", DEV_ID_LOG(d));
794 #ifdef CS_SCCP_CONFERENCE
795 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
796 	if (line) {
797 		sccp_feat_join(d, line, lineInstance, c);
798 	}
799 #else
800 	sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
801 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Conference was not compiled in\n");
802 #endif
803 }
804 
805 /*!
806  * \brief Barge into Call on the Current Line
807  */
sccp_sk_barge(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)808 static void sccp_sk_barge(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
809 {
810 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Barge Pressed\n", DEV_ID_LOG(d));
811 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
812 	if (line) {
813 		sccp_feat_handle_barge(line, lineInstance, d, c);
814 	}
815 }
816 
817 /*!
818  * \brief Barge into Call on the Current Line
819  */
sccp_sk_cbarge(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)820 static void sccp_sk_cbarge(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
821 {
822 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey cBarge Pressed\n", DEV_ID_LOG(d));
823 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
824 	if (line) {
825 		sccp_feat_handle_cbarge(line, lineInstance, d);
826 	}
827 }
828 
829 /*!
830  * \brief Put Current Line in to Meetme Conference
831  * \todo Conferencing option needs to be build and implemented
832  *       Using and External Conference Application Instead of Meetme makes it possible to use app_Conference, app_MeetMe, app_Konference and/or others
833  */
sccp_sk_meetme(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)834 static void sccp_sk_meetme(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
835 {
836 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Meetme Pressed\n", DEV_ID_LOG(d));
837 
838 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
839 	if (line) {
840 		sccp_feat_handle_meetme(line, lineInstance, d);
841 	}
842 }
843 
844 /*!
845  * \brief Pickup Parked Call
846  */
sccp_sk_pickup(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)847 static void sccp_sk_pickup(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
848 {
849 	assert(d != NULL);
850 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Pickup Pressed\n", d->id);
851 #ifndef CS_SCCP_PICKUP
852 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Native EXTENSION PICKUP was not compiled in\n");
853 #else
854 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
855 	if (line) {
856 		AUTO_RELEASE(const sccp_device_t, call_assoc_device, (c ? c->getDevice(c) : NULL));
857 		if (!call_assoc_device || call_assoc_device == d) {
858 			sccp_feat_handle_directed_pickup(d, line, c);
859 			return;
860 		}
861 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: there is already a call:%s present on this (shared)line:%s. Skipping request\n", d->id, c ? c->designator : "SCCP", line->name);
862 	}
863 #endif
864 }
865 
866 /*!
867  * \brief Pickup Ringing Line from Pickup Group
868  */
sccp_sk_gpickup(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)869 static void sccp_sk_gpickup(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
870 {
871 	assert(d != NULL);
872 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Group Pickup Pressed\n", d->id);
873 #ifndef CS_SCCP_PICKUP
874 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Native GROUP PICKUP was not compiled in\n");
875 #else
876 	AUTO_RELEASE(const sccp_line_t, line , sccp_sk_get_retained_line(d, l, lineInstance, c, SKINNY_DISP_NO_LINE_AVAILABLE));
877 	if (line) {
878 		AUTO_RELEASE(const sccp_device_t, call_assoc_device, (c ? c->getDevice(c) : NULL));
879 		if (!call_assoc_device || call_assoc_device == d) {
880 			sccp_feat_grouppickup(d, line, lineInstance, c);
881 			return;
882 		}
883 		sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: there is already a call:%s present on this (shared)line:%s. Skipping request\n", d->id, c ? c->designator : "SCCP", line->name);
884 	}
885 #endif
886 }
887 
sccp_sk_info(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr none)888 static void sccp_sk_info(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr none)
889 {
890 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Info Pressed\n", DEV_ID_LOG(d));
891 	sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
892 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Info Softkey not (yet) supported\n");
893 }
894 
sccp_sk_callback(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)895 static void sccp_sk_callback(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
896 {
897 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Callback Pressed\n", DEV_ID_LOG(d));
898 	sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
899 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Callback Softkey not (yet) supported\n");
900 }
901 
sccp_sk_empty(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr none)902 static void sccp_sk_empty(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr none)
903 {
904 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Empty Pressed\n", DEV_ID_LOG(d));
905 	sccp_dev_displayprompt(d, lineInstance, 0, SKINNY_DISP_KEY_IS_NOT_ACTIVE, SCCP_DISPLAYSTATUS_TIMEOUT);
906 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "### Empty Softkey not supported\n");
907 }
908 
909 /*!
910  * \brief Execute URI(s)
911  */
sccp_sk_uriaction(const sccp_softkeyMap_cb_t * const softkeyMap_cb,constDevicePtr d,constLinePtr l,const uint32_t lineInstance,channelPtr c)912 static void sccp_sk_uriaction(const sccp_softkeyMap_cb_t * const softkeyMap_cb, constDevicePtr d, constLinePtr l, const uint32_t lineInstance, channelPtr c)
913 {
914 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: SoftKey Pressed\n", DEV_ID_LOG(d));
915 	if (!d) {
916 		return;
917 	}
918 	unsigned int transactionID = sccp_random();
919 
920 	/* build parameters */
921 	struct ast_str *paramStr = pbx_str_alloca(DEFAULT_PBX_STR_BUFFERSIZE);
922 	if (!paramStr) {
923 		pbx_log(LOG_ERROR, SS_Memory_Allocation_Error, "SCCP");
924 		return;
925 	}
926 	ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "name=%s", d->id);
927 	ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;softkey=%s", label2str(softkeyMap_cb->event));
928 	if (l) {
929 		ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;line=%s", l->name);
930 	}
931 	if (lineInstance) {
932 		ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;lineInstance=%d", lineInstance);
933 	}
934 	if (c) {
935 		ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;channel=%s", c->designator);
936 		ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;callid=%d", c->callid);
937 		if (c->owner) {
938 			ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;linkedid=%s", iPbx.getChannelLinkedId(c));
939 			ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;uniqueid=%s", pbx_channel_uniqueid(c->owner));
940 		}
941 	}
942 	ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;appID=%d", APPID_URIHOOK);
943 	ast_str_append(&paramStr, DEFAULT_PBX_STR_BUFFERSIZE, "&amp;transactionID=%d", transactionID);
944 
945 	/* build xmlStr */
946 	struct ast_str *xmlStr = pbx_str_alloca(DEFAULT_PBX_STR_BUFFERSIZE);
947 	if (!xmlStr) {
948 		pbx_log(LOG_ERROR, SS_Memory_Allocation_Error, "SCCP");
949 		return;
950 	}
951 
952 	ast_str_append(&xmlStr, DEFAULT_PBX_STR_BUFFERSIZE, "%s", "<CiscoIPPhoneExecute>");
953 
954 	char delims[] = ",";
955 	char *uris = pbx_strdupa(softkeyMap_cb->uriactionstr);
956 	char *tokenrest = NULL;
957 	char *token = strtok_r(uris, delims, &tokenrest);
958 
959 	while (token) {
960 		token = sccp_trimwhitespace(token);
961 		if (!strncasecmp("http:", token, 5)) {
962 			if (!strchr(token, '?')) {
963 				ast_str_append(&xmlStr, DEFAULT_PBX_STR_BUFFERSIZE, "<ExecuteItem Priority=\"0\" URL=\"%s?%s\"/>", token, pbx_str_buffer(paramStr));
964 			} else {
965 				ast_str_append(&xmlStr, DEFAULT_PBX_STR_BUFFERSIZE, "<ExecuteItem Priority=\"0\" URL=\"%s&amp;%s\"/>", token, pbx_str_buffer(paramStr));
966 			}
967 		} else {
968 			ast_str_append(&xmlStr, DEFAULT_PBX_STR_BUFFERSIZE, "<ExecuteItem Priority=\"0\" URL=\"%s\"/>", token);
969 		}
970 		token = strtok_r(NULL, delims, &tokenrest);
971 	}
972 	ast_str_append(&xmlStr, DEFAULT_PBX_STR_BUFFERSIZE, "%s", "</CiscoIPPhoneExecute>");
973 
974 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: Send '%s' to Phone\n", DEV_ID_LOG(d), pbx_str_buffer(xmlStr));
975 	d->protocol->sendUserToDeviceDataVersionMessage(d, APPID_URIHOOK, lineInstance, c ? c->callid : 0, transactionID, pbx_str_buffer(xmlStr), 0);
976 }
977 
978 /*!
979  * \brief Softkey Function Callback by SKINNY LABEL
980  */
981 static const struct sccp_softkeyMap_cb softkeyCbMap[] = {
982 	{SKINNY_LBL_REDIAL, FALSE, sccp_sk_redial, NULL},
983 	{SKINNY_LBL_NEWCALL, FALSE, sccp_sk_newcall, NULL},
984 	{SKINNY_LBL_HOLD, TRUE, sccp_sk_hold, NULL},
985 	{SKINNY_LBL_TRANSFER, TRUE, sccp_sk_transfer, NULL},
986 	{SKINNY_LBL_CFWDALL, FALSE, sccp_sk_cfwdall, NULL},
987 	{SKINNY_LBL_CFWDBUSY, FALSE, sccp_sk_cfwdbusy, NULL},
988 	{SKINNY_LBL_CFWDNOANSWER, FALSE, sccp_sk_cfwdnoanswer, NULL},
989 	{SKINNY_LBL_BACKSPACE, TRUE, sccp_sk_backspace, NULL},
990 	{SKINNY_LBL_ENDCALL, TRUE, sccp_sk_endcall, NULL},
991 	{SKINNY_LBL_RESUME, TRUE, sccp_sk_resume, NULL},
992 	{SKINNY_LBL_ANSWER, TRUE, sccp_sk_answer, NULL},
993 	{SKINNY_LBL_INFO, FALSE, sccp_sk_info, NULL},
994 	{SKINNY_LBL_CONFRN, TRUE, sccp_sk_conference, NULL},
995 	{SKINNY_LBL_PARK, TRUE, sccp_sk_park, NULL},
996 	{SKINNY_LBL_JOIN, TRUE, sccp_sk_join, NULL},
997 	{SKINNY_LBL_MEETME, TRUE, sccp_sk_meetme, NULL},
998 	{SKINNY_LBL_PICKUP, FALSE, sccp_sk_pickup, NULL},
999 	{SKINNY_LBL_GPICKUP, FALSE, sccp_sk_gpickup, NULL},
1000 	{SKINNY_LBL_MONITOR, TRUE, sccp_sk_monitor, NULL},
1001 	{SKINNY_LBL_CALLBACK, TRUE, sccp_sk_callback, NULL},
1002 	{SKINNY_LBL_BARGE, TRUE, sccp_sk_barge, NULL},
1003 	{SKINNY_LBL_DND, FALSE, sccp_sk_dnd, NULL},
1004 	{SKINNY_LBL_CONFLIST, TRUE, sccp_sk_conflist, NULL},
1005 	{SKINNY_LBL_SELECT, TRUE, sccp_sk_select, NULL},
1006 	{SKINNY_LBL_PRIVATE, FALSE, sccp_sk_private, NULL},
1007 	{SKINNY_LBL_TRNSFVM, TRUE, sccp_sk_trnsfvm, NULL},
1008 	{SKINNY_LBL_DIRTRFR, TRUE, sccp_sk_dirtrfr, NULL},
1009 	{SKINNY_LBL_IDIVERT, TRUE, sccp_sk_trnsfvm, NULL},
1010 	{SKINNY_LBL_VIDEO_MODE, TRUE, sccp_sk_videomode, NULL},
1011 	{SKINNY_LBL_INTRCPT, TRUE, sccp_sk_resume, NULL},
1012 	{SKINNY_LBL_EMPTY, FALSE, sccp_sk_empty, NULL},
1013 	{SKINNY_LBL_DIAL, TRUE, sccp_sk_dial, NULL},
1014 	{SKINNY_LBL_CBARGE, TRUE, sccp_sk_cbarge, NULL},
1015 };
1016 
1017 /*!
1018  * \brief Get SoftkeyMap by Event
1019  */
sccp_getSoftkeyMap_by_SoftkeyEvent(constDevicePtr d,uint32_t event)1020 gcc_inline static const sccp_softkeyMap_cb_t *sccp_getSoftkeyMap_by_SoftkeyEvent(constDevicePtr d, uint32_t event)
1021 {
1022 	uint8_t i = 0;
1023 
1024 	const sccp_softkeyMap_cb_t *mySoftkeyCbMap = softkeyCbMap;
1025 
1026 	if (d->softkeyset && d->softkeyset->softkeyCbMap) {
1027 		mySoftkeyCbMap = d->softkeyset->softkeyCbMap;
1028 	}
1029 	sccp_log(DEBUGCAT_SOFTKEY) (VERBOSE_PREFIX_3 "%s: (sccp_getSoftkeyMap_by_SoftkeyEvent) default: %p, softkeyset: %p, softkeyCbMap: %p\n", d->id, softkeyCbMap, d->softkeyset, d->softkeyset ? d->softkeyset->softkeyCbMap : NULL);
1030 
1031 	for (i = 0; i < ARRAY_LEN(softkeyCbMap); i++) {
1032 		if (mySoftkeyCbMap[i].event == event) {
1033 			return &mySoftkeyCbMap[i];
1034 		}
1035 	}
1036 	return NULL;
1037 }
1038 
1039 /* =========================================================================================== Public */
1040 
1041 /*!
1042  * \brief Softkey Pre Reload
1043  *
1044  */
sccp_softkey_pre_reload(void)1045 void sccp_softkey_pre_reload(void)
1046 {
1047 	sccp_softkey_clear();
1048 }
1049 
1050 /*!
1051  * \brief Softkey Post Reload
1052  */
sccp_softkey_post_reload(void)1053 void sccp_softkey_post_reload(void)
1054 {
1055 	/* only required because softkeys are parsed after devices */
1056 	/* incase softkeysets have changed but device was not reloaded, then d->softkeyset needs to be fixed up */
1057 	sccp_device_t * d = NULL;
1058 	SCCP_RWLIST_RDLOCK(&GLOB(devices));
1059 	SCCP_RWLIST_TRAVERSE(&GLOB(devices), d, list) {
1060 		sccp_softKeySetConfiguration_t * softkeyset = NULL;
1061 		SCCP_LIST_LOCK(&softKeySetConfig);
1062 		SCCP_LIST_TRAVERSE(&softKeySetConfig, softkeyset, list) {
1063 			if(sccp_strcaseequals(d->softkeyDefinition, softkeyset->name)) {
1064 				sccp_log((DEBUGCAT_CONFIG + DEBUGCAT_SOFTKEY))(VERBOSE_PREFIX_3 "Re-attaching softkeyset: %s to device d: %s\n", softkeyset->name, d->id);
1065 				d->softkeyset = softkeyset;
1066 				d->softKeyConfiguration.modes = softkeyset->modes;
1067 				d->softKeyConfiguration.size = softkeyset->numberOfSoftKeySets;
1068 			}
1069 		}
1070 		SCCP_LIST_UNLOCK(&softKeySetConfig);
1071 	}
1072 	SCCP_RWLIST_UNLOCK(&GLOB(devices));
1073 }
1074 
1075 /*!
1076  * \brief Softkey Clear (Unload/Reload)
1077  */
sccp_softkey_clear(void)1078 void sccp_softkey_clear(void)
1079 {
1080 	sccp_softKeySetConfiguration_t * k = NULL;
1081 	uint8_t i = 0;
1082 
1083 	SCCP_LIST_LOCK(&softKeySetConfig);
1084 	while ((k = SCCP_LIST_REMOVE_HEAD(&softKeySetConfig, list))) {
1085 		for (i = 0; i < StationMaxSoftKeySetDefinition; i++) {
1086 			if (k->modes[i].ptr) {
1087 				//sccp_log((DEBUGCAT_CONFIG + DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "Freeing KeyMode Ptr: %p for KeyMode %i\n", k->modes[i].ptr, i);
1088 				sccp_free(k->modes[i].ptr);
1089 				k->modes[i].count = 0;
1090 			}
1091 		}
1092 		if (k->softkeyCbMap) {
1093 			for (i = 0; i < ARRAY_LEN(softkeyCbMap); i++) {
1094 				if (!sccp_strlen_zero(k->softkeyCbMap[i].uriactionstr)) {
1095 					sccp_free(k->softkeyCbMap[i].uriactionstr);
1096 				}
1097 			}
1098 			sccp_free(k->softkeyCbMap);
1099 		}
1100 		//sccp_log((DEBUGCAT_CONFIG + DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "Softkeyset: %s removed\n", k->name);
1101 		sccp_free(k);
1102 	}
1103 	SCCP_LIST_UNLOCK(&softKeySetConfig);
1104 }
1105 
1106 /*!
1107  * \brief Return a Copy of the statically defined SoftkeyMap
1108  * \note malloc, needs to be freed
1109  */
sccp_softkeyMap_copyStaticallyMapped(void)1110 sccp_softkeyMap_cb_t __attribute__ ((malloc)) * sccp_softkeyMap_copyStaticallyMapped(void)
1111 {
1112 	sccp_softkeyMap_cb_t *newSoftKeyMap = (sccp_softkeyMap_cb_t *) sccp_malloc((sizeof *newSoftKeyMap) * ARRAY_LEN(softkeyCbMap));
1113 	if (!newSoftKeyMap) {
1114 		pbx_log(LOG_ERROR, SS_Memory_Allocation_Error, "SCCP");
1115 		return NULL;
1116 	}
1117 	memcpy(newSoftKeyMap, softkeyCbMap, ARRAY_LEN(softkeyCbMap) * sizeof(sccp_softkeyMap_cb_t));
1118 	sccp_log(DEBUGCAT_SOFTKEY) (VERBOSE_PREFIX_3 "SCCP: (sccp_softkeyMap_copyIfStaticallyMapped) Created copy of static version, returning: %p\n", newSoftKeyMap);
1119 	return newSoftKeyMap;
1120 }
1121 
1122 /*!
1123  * \brief Replace a specific softkey callback entry by sccp_sk_uriaction and fill it's uriactionstr
1124  * \note pbx_strdup, needs to be freed
1125  */
sccp_softkeyMap_replaceCallBackByUriAction(sccp_softkeyMap_cb_t * const softkeyMap,uint32_t event,char * uriactionstr)1126 boolean_t sccp_softkeyMap_replaceCallBackByUriAction(sccp_softkeyMap_cb_t * const softkeyMap, uint32_t event, char *uriactionstr)
1127 {
1128 	sccp_log(DEBUGCAT_SOFTKEY) (VERBOSE_PREFIX_3 "SCCP: (sccp_softkeyMap_replaceCallBackByUriHook) %p, event: %s, uriactionstr: %s\n", softkeyMap, label2str(event), uriactionstr);
1129 	for(uint i = 0; i < ARRAY_LEN(softkeyCbMap); i++) {
1130 		if (event == softkeyMap[i].event) {
1131 			softkeyMap[i].softkeyEvent_cb = sccp_sk_uriaction;
1132 			softkeyMap[i].uriactionstr = pbx_strdup(sccp_trimwhitespace(uriactionstr));
1133 			return TRUE;
1134 		}
1135 	}
1136 	return FALSE;
1137 }
1138 
1139 /*!
1140  * \brief Execute Softkey Callback by SofkeyEvent
1141  */
sccp_SoftkeyMap_execCallbackByEvent(devicePtr d,linePtr l,uint32_t lineInstance,channelPtr c,uint32_t event)1142 boolean_t sccp_SoftkeyMap_execCallbackByEvent(devicePtr d, linePtr l, uint32_t lineInstance, channelPtr c, uint32_t event)
1143 {
1144 	if (!d || !event) {
1145 		pbx_log(LOG_ERROR, "SCCP: (sccp_execSoftkeyMapCb_by_SoftkeyEvent) no device or event provided\n");
1146 		return FALSE;
1147 	}
1148 	const sccp_softkeyMap_cb_t *softkeyMap_cb = sccp_getSoftkeyMap_by_SoftkeyEvent(d, event);
1149 
1150 	if (!softkeyMap_cb) {
1151 		pbx_log(LOG_WARNING, "%s: Don't know how to handle keypress %d\n", d->id, event);
1152 		return FALSE;
1153 	}
1154 	if (softkeyMap_cb->channelIsNecessary == TRUE && !c) {
1155 		pbx_log(LOG_WARNING, "%s: Channel required to handle keypress %d\n", d->id, event);
1156 		return FALSE;
1157 	}
1158 	sccp_log((DEBUGCAT_SOFTKEY))(VERBOSE_PREFIX_3 "%s: Handling Softkey: %s on line: %s and channel: %s\n", d->id, label2str(event), l ? l->name : "UNDEF", c ? c->designator : "UNDEF");
1159 
1160 	softkeyMap_cb->softkeyEvent_cb(softkeyMap_cb, d, l, lineInstance, c);
1161 	return TRUE;
1162 }
1163 
1164 /*!
1165  * \brief Enable or Disable one softkey on a specific softKeySet
1166  */
sccp_softkey_setSoftkeyState(devicePtr device,skinny_keymode_t softKeySet,uint8_t softKey,boolean_t enable)1167 void sccp_softkey_setSoftkeyState(devicePtr device, skinny_keymode_t softKeySet, uint8_t softKey, boolean_t enable)
1168 {
1169 	if (!device || !device->softKeyConfiguration.size) {
1170 		return;
1171 	}
1172 
1173 	sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_3 "%s: softkey '%s' on %s to %s\n", DEV_ID_LOG(device), label2str(softKey), skinny_keymode2str(softKeySet), enable ? "on" : "off");
1174 	/* find softkey */
1175 	for(uint8_t i = 0; i < device->softKeyConfiguration.modes[softKeySet].count; i++) {
1176 		if (device->softKeyConfiguration.modes[softKeySet].ptr && device->softKeyConfiguration.modes[softKeySet].ptr[i] == softKey) {
1177 			sccp_log((DEBUGCAT_SOFTKEY)) (VERBOSE_PREFIX_4 "%s: found softkey '%s' at %d\n", DEV_ID_LOG(device), label2str(device->softKeyConfiguration.modes[softKeySet].ptr[i]), i);
1178 			if (enable) {
1179 				device->softKeyConfiguration.activeMask[softKeySet] |= (1 << i);
1180 			} else {
1181 				device->softKeyConfiguration.activeMask[softKeySet] &= (~(1 << i));
1182 			}
1183 		}
1184 	}
1185 }
1186 
sccp_softkey_isSoftkeyInSoftkeySet(constDevicePtr device,const skinny_keymode_t softKeySet,const uint8_t softKey)1187 boolean_t __PURE__ sccp_softkey_isSoftkeyInSoftkeySet(constDevicePtr device, const skinny_keymode_t softKeySet, const uint8_t softKey)
1188 {
1189 	if (!device || !device->softKeyConfiguration.size) {
1190 		return FALSE;
1191 	}
1192 
1193 	/* find softkey */
1194 	for(uint8_t i = 0; i < device->softKeyConfiguration.modes[softKeySet].count; i++) {
1195 		if (device->softKeyConfiguration.modes[softKeySet].ptr && device->softKeyConfiguration.modes[softKeySet].ptr[i] == softKey) {
1196 			return TRUE;
1197 		}
1198 	}
1199 	return FALSE;
1200 }
1201 // 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;
1202