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(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "name=%s", d->id);
927 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&softkey=%s", label2str(softkeyMap_cb->event));
928 if (l) {
929 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&line=%s", l->name);
930 }
931 if (lineInstance) {
932 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&lineInstance=%d", lineInstance);
933 }
934 if (c) {
935 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&channel=%s", c->designator);
936 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&callid=%d", c->callid);
937 if (c->owner) {
938 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&linkedid=%s", iPbx.getChannelLinkedId(c));
939 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&uniqueid=%s", pbx_channel_uniqueid(c->owner));
940 }
941 }
942 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&appID=%d", APPID_URIHOOK);
943 ast_str_append(¶mStr, DEFAULT_PBX_STR_BUFFERSIZE, "&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&%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