1 /*!
2 * \file sccp_indicate.c
3 * \brief SCCP Indicate 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 *
10 */
11
12 #include "config.h"
13 #include "common.h"
14 #include "sccp_channel.h"
15 #include "sccp_conference.h"
16 #include "sccp_actions.h"
17 #include "sccp_device.h"
18 #include "sccp_indicate.h"
19 #include "sccp_line.h"
20 #include "sccp_linedevice.h"
21 #include "sccp_utils.h"
22 #include "sccp_labels.h"
23
24 SCCP_FILE_VERSION(__FILE__, "");
25
26 static void __sccp_indicate_remote_device(constDevicePtr device, channelPtr c, linePtr line, const sccp_channelstate_t state);
27
28 /*!
29 * \brief Indicate Without Lock
30 * \param device SCCP Device
31 * \param c *locked* SCCP Channel
32 * \param state State as uint8_t
33 * \param debug Debug as uint8_t
34 * \param file File as char
35 * \param line Line Number as int
36 * \param file Pretty Function as char
37 * \param pretty_function
38 *
39 * \callgraph
40 * \callergraph
41 *
42 * \warning
43 * - line->devices is not always locked
44 *
45 */
46 //void __sccp_indicate(sccp_device_t * _device, sccp_channel_t * c, uint8_t state, uint8_t debug, char *file, int line, const char *pretty_function)
__sccp_indicate(constDevicePtr maybe_device,channelPtr c,const sccp_channelstate_t state,boolean_t force,const uint8_t debug,const char * file,const int line,const char * pretty_function)47 void __sccp_indicate (constDevicePtr maybe_device, channelPtr c, const sccp_channelstate_t state, boolean_t force, const uint8_t debug, const char * file, const int line, const char * pretty_function)
48 {
49 if (debug) {
50 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_1 "SCCP: [INDICATE] state '%d' in file '%s', on line %d (%s)\n", state, file, line, pretty_function);
51 }
52
53 AUTO_RELEASE(sccp_device_t, d , (maybe_device) ? sccp_device_retain(maybe_device) : sccp_channel_getDevice(c));
54 if (!d) {
55 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_1 "SCCP: The channel %d does not have a device\n", c->callid);
56 return;
57 }
58
59 AUTO_RELEASE(sccp_line_t, l , sccp_line_retain(c->line));
60 if (!l) {
61 pbx_log(LOG_ERROR, "SCCP: The channel %d does not have a line\n", c->callid);
62 return;
63 }
64 uint16_t lineInstance = sccp_device_find_index_for_line(d, l->name);
65
66 /* all the check are ok. We can safely run all the dev functions with no more checks */
67 sccp_log((DEBUGCAT_INDICATE + DEBUGCAT_DEVICE + DEBUGCAT_LINE)) (VERBOSE_PREFIX_3 "%s: Indicate SCCP new state:%s, current channel state:%s on call:%s, lineInstance:%d (previous channelstate:%s)\n", d->id, sccp_channelstate2str(state), sccp_channelstate2str(c->state), c->designator, lineInstance, sccp_channelstate2str(c->previousChannelState));
68 sccp_channel_setChannelstate(c, state);
69 sccp_callinfo_t * const ci = sccp_channel_getCallInfo(c);
70
71 if (SCCP_CHANNELSTATE_Idling(state) || SCCP_CHANNELSTATE_IsTerminating(state)) {
72 sccp_device_indicateMWI(d);
73 } else {
74 sccp_device_suppressMWI(d);
75 }
76 switch (state) {
77 case SCCP_CHANNELSTATE_DOWN:
78 {
79 //iPbx.set_callstate(c, AST_STATE_DOWN);
80 }
81 break;
82 case SCCP_CHANNELSTATE_OFFHOOK:
83 {
84 // should use d->indicate->offhook instead
85 sccp_dev_set_speaker(d, SKINNY_STATIONSPEAKER_ON);
86 sccp_device_setLamp(d, SKINNY_STIMULUS_LINE, lineInstance, SKINNY_LAMP_ON);
87 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_OFFHOOK, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
88 sccp_dev_set_cplane(d, lineInstance, 1);
89 if(SCCP_CHANNELSTATE_DOWN == c->previousChannelState) { // new call
90 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_ENTER_NUMBER, GLOB(digittimeout));
91 c->setTone(c, l->initial_dialtone_tone, SKINNY_TONEDIRECTION_USER);
92 if(!(d->hasMWILight()) && d->voicemailStatistic.newmsgs) {
93 sccp_log((DEBUGCAT_INDICATE | DEBUGCAT_MWI))(VERBOSE_PREFIX_2 "%s: Device does not have MWI-light and does have messages waiting -> stutter\n", d->id);
94 c->setTone(c, SKINNY_TONE_PARTIALDIALTONE, SKINNY_TONEDIRECTION_USER); /* Add Stutter Pattern for ATA/Analog devices */
95 }
96 }
97 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_OFFHOOK);
98 }
99 break;
100 case SCCP_CHANNELSTATE_GETDIGITS:
101 {
102 c->state = SCCP_CHANNELSTATE_OFFHOOK;
103 sccp_dev_set_speaker(d, SKINNY_STATIONSPEAKER_ON);
104 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_OFFHOOK, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
105 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_ENTER_NUMBER, GLOB(digittimeout));
106 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_DIGITSFOLL);
107 sccp_dev_set_cplane(d, lineInstance, 1);
108 c->setTone(c, SKINNY_TONE_ZIP, SKINNY_TONEDIRECTION_USER);
109 }
110 break;
111 case SCCP_CHANNELSTATE_DIGITSFOLL:
112 {
113 int lenDialed = sccp_strlen(c->dialedNumber);
114 int lenSecDialtoneDigits = sccp_strlen(l->secondary_dialtone_digits);
115 skinny_tone_t secondary_dialtone_tone = l->secondary_dialtone_tone;
116 sccp_log(DEBUGCAT_INDICATE)(VERBOSE_PREFIX_3 "%s: digitsfollow: dialed:%s, lenDialed:%d, secDialtoneDigits:%s, lenSecDialtoneDigits:%d, secondary_dialtine:%d\n",
117 c->designator,
118 c->dialedNumber,
119 lenDialed,
120 l->secondary_dialtone_digits,
121 lenSecDialtoneDigits,
122 secondary_dialtone_tone);
123 if (lenSecDialtoneDigits > 0 && lenDialed == lenSecDialtoneDigits && !strncmp(c->dialedNumber, l->secondary_dialtone_digits, lenSecDialtoneDigits)) {
124 c->setTone(c, secondary_dialtone_tone, SKINNY_TONEDIRECTION_USER);
125 } else if (lenDialed > 0) {
126 c->setTone(c, SKINNY_TONE_SILENCE, SKINNY_TONEDIRECTION_USER);
127 }
128 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_DIGITSFOLL);
129 break;
130 }
131 case SCCP_CHANNELSTATE_SPEEDDIAL:
132 {
133 c->state = SCCP_CHANNELSTATE_OFFHOOK;
134 /* clear all the display buffers */
135 sccp_dev_cleardisplaynotify(d);
136 sccp_dev_clearprompt(d, 0, 0);
137
138 sccp_dev_set_ringer(d, SKINNY_RINGTYPE_OFF, SKINNY_RINGDURATION_NORMAL, lineInstance, c->callid);
139 sccp_dev_set_speaker(d, SKINNY_STATIONSPEAKER_ON);
140 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_OFFHOOK, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
141 //sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_ENTER_NUMBER, GLOB(digittimeout));
142 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_OFFHOOK);
143 sccp_dev_set_cplane(d, lineInstance, 1);
144 }
145 break;
146 case SCCP_CHANNELSTATE_DIALING:
147 {
148 if (c->previousChannelState == SCCP_CHANNELSTATE_DIALING) {
149 break;
150 }
151 d->indicate->dialing(d, lineInstance, c->callid, c->calltype, ci, c->dialedNumber);
152 }
153 break;
154 case SCCP_CHANNELSTATE_RINGOUT:
155 {
156 // we already send out the ringing state before */
157 // first ringout indicate (before connected line update */
158 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_PROCEED, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
159 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_RING_OUT, GLOB(digittimeout));
160 if (!(sccp_rtp_getState (&c->rtp.audio, SCCP_RTP_RECEPTION) & SCCP_RTP_STATUS_ACTIVE)) {
161 c->setTone (c, SKINNY_TONE_ALERTINGTONE, SKINNY_TONEDIRECTION_USER);
162 }
163 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_RINGOUT);
164 iCallInfo.Send(ci, c->callid, c->calltype, lineInstance, d, FALSE);
165 }
166 break;
167 case SCCP_CHANNELSTATE_RINGOUT_ALERTING:
168 /* send by connected line update, to show that we know the remote end, we can now update the callinfo */
169 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_RINGOUT, SKINNY_CALLPRIORITY_NORMAL, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
170 iCallInfo.Send(ci, c->callid, c->calltype, lineInstance, d, TRUE);
171 break;
172 case SCCP_CHANNELSTATE_RINGING:
173 {
174 sccp_dev_cleardisplaynotify(d);
175 sccp_dev_clearprompt(d, lineInstance, 0);
176
177 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_RINGIN, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
178 iCallInfo.Send(ci, c->callid, c->calltype, lineInstance, d, TRUE);
179 sccp_device_setLamp(d, SKINNY_STIMULUS_LINE, lineInstance, SKINNY_LAMP_BLINK);
180
181 if ((d->dndFeature.enabled && d->dndFeature.status == SCCP_DNDMODE_SILENT && c->ringermode != SKINNY_RINGTYPE_URGENT)) {
182 sccp_log((DEBUGCAT_INDICATE + DEBUGCAT_CHANNEL)) (VERBOSE_PREFIX_3 "%s: DND is active on device\n", d->id);
183 sccp_dev_set_ringer(d, SKINNY_RINGTYPE_SILENT, SKINNY_RINGDURATION_NORMAL, lineInstance, c->callid);
184 if (GLOB(dnd_tone) && d->dndFeature.status == SCCP_DNDMODE_SILENT) {
185 sccp_dev_starttone(d, GLOB(dnd_tone), 0, 0, SKINNY_TONEDIRECTION_USER);
186 }
187 } else {
188 sccp_linedevice_t * ownlinedevice = NULL;
189 sccp_device_t *remoteDevice = NULL;
190
191 SCCP_LIST_TRAVERSE(&l->devices, ownlinedevice, list) {
192 remoteDevice = ownlinedevice->device;
193
194 if (d && remoteDevice && remoteDevice == d) {
195 sccp_log((DEBUGCAT_INDICATE + DEBUGCAT_CHANNEL))(VERBOSE_PREFIX_3 "%s: Found matching ld. Aux parameter = %s\n", d->id, ownlinedevice->subscriptionId.aux);
196 if (0 == strncmp(ownlinedevice->subscriptionId.aux, "silent", 6)) {
197 sccp_dev_set_ringer(d, SKINNY_RINGTYPE_SILENT, SKINNY_RINGDURATION_NORMAL, lineInstance, c->callid);
198 sccp_log((DEBUGCAT_INDICATE + DEBUGCAT_CHANNEL))(VERBOSE_PREFIX_3 "%s: Forcing silent ring for specific device.\n", d->id);
199 } else {
200 sccp_dev_set_ringer(d, c->ringermode, SKINNY_RINGDURATION_NORMAL, lineInstance, c->callid);
201 sccp_log((DEBUGCAT_INDICATE + DEBUGCAT_CHANNEL)) (VERBOSE_PREFIX_3 "%s: Normal ring occurred.\n", d->id);
202 }
203 }
204 }
205 }
206
207 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_RINGIN);
208 char prompt[100];
209
210 char orig_called_name[StationMaxNameSize] = {0};
211 char orig_called_num[StationMaxDirnumSize] = {0};
212 char calling_name[StationMaxNameSize] = {0};
213 char calling_num[StationMaxDirnumSize] = {0};
214 iCallInfo.Getter(ci,
215 SCCP_CALLINFO_ORIG_CALLEDPARTY_NAME, &orig_called_name,
216 SCCP_CALLINFO_ORIG_CALLEDPARTY_NUMBER, &orig_called_num,
217 SCCP_CALLINFO_CALLINGPARTY_NAME, &calling_name,
218 SCCP_CALLINFO_CALLINGPARTY_NUMBER, &calling_num,
219 SCCP_CALLINFO_KEY_SENTINEL);
220
221 /* GPL - Modify below to expand possible data shown on phone */
222 char caller[100];
223 if (!sccp_strlen_zero(calling_name)) {
224 if (!sccp_strlen_zero(calling_num)) {
225 snprintf(caller,sizeof(caller), "%s (%s)", calling_name, calling_num);
226 } else {
227 snprintf(caller,sizeof(caller), "%s", calling_name);
228 }
229 } else {
230 if (!sccp_strlen_zero(calling_num)) {
231 snprintf(caller,sizeof(caller), "%s", calling_num);
232 } else {
233 snprintf(caller,sizeof(caller), "%s", SKINNY_DISP_UNKNOWN_NUMBER);
234 }
235 }
236 snprintf(prompt, sizeof(prompt), "%s%s", (c->ringermode == SKINNY_RINGTYPE_URGENT) ? SKINNY_DISP_FLASH : SKINNY_DISP_FROM, caller);
237 sccp_dev_displayprompt(d, lineInstance, c->callid, prompt, GLOB(digittimeout));
238 }
239 break;
240 case SCCP_CHANNELSTATE_PROGRESS:
241 sccp_log(DEBUGCAT_RTP)(VERBOSE_PREFIX_3 "%s (%s) wantsEarlyRTP:%s, progressSent:%s\n", c->designator, __func__, c->wantsEarlyRTP() ? "yes" : "no", c->progressSent() ? "yes" : "no");
242 if(!c->wantsEarlyRTP()) {
243 // work around : FreePBX sometimes goes from DIALING->AST_CONTROL_PROGRESS skipping RINGING (for EarlyRTP=off)
244 if(c->previousChannelState == SCCP_CHANNELSTATE_DIALING) {
245 sccp_indicate(d, c, SCCP_CHANNELSTATE_RINGOUT);
246 } else if(c->previousChannelState == SCCP_CHANNELSTATE_RINGOUT) {
247 sccp_indicate(d, c, SCCP_CHANNELSTATE_RINGOUT_ALERTING);
248 }
249 } else if(!c->progressSent()) {
250 c->makeProgress(c);
251 }
252 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_CALL_PROGRESS, GLOB(digittimeout));
253 break;
254 case SCCP_CHANNELSTATE_PROCEED:
255 {
256 if (c->previousChannelState == SCCP_CHANNELSTATE_CONNECTED) { // this is a bug of asterisk 1.6 (it sends progress after a call is answered then diverted to some extensions with dial app)
257 sccp_log((DEBUGCAT_INDICATE + DEBUGCAT_CHANNEL)) (VERBOSE_PREFIX_3 "SCCP: Asterisk requests to change state to (Progress) after (Connected). Ignoring\n");
258 break;
259 }
260 d->indicate->proceed(d, lineInstance, c->callid, c->calltype, ci);
261 }
262 break;
263 case SCCP_CHANNELSTATE_CALLREMOTEMULTILINE:
264 {
265 sccp_dev_set_ringer(d, SKINNY_RINGTYPE_OFF, SKINNY_RINGDURATION_NORMAL, lineInstance, c->callid);
266 sccp_dev_clearprompt(d, lineInstance, c->callid);
267 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_CONNECTED, SKINNY_CALLPRIORITY_NORMAL, SKINNY_CALLINFO_VISIBILITY_DEFAULT); /** send connected, so it is not listed as missed call */
268 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_CALLREMOTEMULTILINE, SKINNY_CALLPRIORITY_NORMAL, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
269 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_ONHOOKSTEALABLE);
270 }
271 break;
272 case SCCP_CHANNELSTATE_CONNECTED:
273 {
274 d->indicate->connected(d, lineInstance, c->callid, c->calltype, ci);
275 sccp_rtp_setCallback(&c->rtp.audio, SCCP_RTP_RECEPTION, sccp_channel_startMediaTransmission);
276 if(!sccp_rtp_getState(&c->rtp.audio, SCCP_RTP_RECEPTION)) {
277 sccp_channel_openReceiveChannel(c);
278 } else if(!sccp_rtp_getState(&c->rtp.audio, SCCP_RTP_TRANSMISSION)) {
279 /* this looks a little confusing, maybe we should not have two but only one rtp callback */
280 sccp_rtp_runCallback(&c->rtp.audio, SCCP_RTP_RECEPTION, c);
281 } else {
282 sccp_rtp_setCallback(&c->rtp.audio, SCCP_RTP_RECEPTION, NULL);
283 }
284 c->setTone (c, SKINNY_TONE_SILENCE, SKINNY_TONEDIRECTION_USER);
285 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_CONNECTED);
286 }
287 break;
288 case SCCP_CHANNELSTATE_BUSY:
289 {
290 if(!sccp_rtp_getState(&c->rtp.audio, SCCP_RTP_RECEPTION)) {
291 c->setTone(c, SKINNY_TONE_LINEBUSYTONE, SKINNY_TONEDIRECTION_USER);
292 }
293 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_BUSY, GLOB(digittimeout));
294 }
295 break;
296 case SCCP_CHANNELSTATE_HOLD:
297 {
298 sccp_channel_closeAllMediaTransmitAndReceive(c);
299 if (d->session) {
300 sccp_handle_time_date_req(d->session, d, NULL);
301 }
302 sccp_device_setLamp(d, SKINNY_STIMULUS_LINE, lineInstance, SKINNY_LAMP_WINK);
303 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_HOLD, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT); /* send connected, so it is not listed as missed call */
304 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_HOLD, GLOB(digittimeout));
305 iCallInfo.Send(ci, c->callid, c->calltype, lineInstance, d, TRUE);
306 sccp_dev_set_speaker(d, SKINNY_STATIONSPEAKER_OFF);
307 #if CS_SCCP_CONFERENCE
308 if (c->conference && d->conference) {
309 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_HOLDCONF);
310 } else
311 #endif
312 {
313 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_ONHOLD);
314 }
315 }
316 break;
317 case SCCP_CHANNELSTATE_CALLWAITING:
318 {
319 /* When dialing a shared line which you also have registered, we don't want the outgoing call to show up on our own device as a callwaiting call */
320 AUTO_RELEASE(sccp_channel_t, activeChannel, sccp_device_getActiveChannel(d));
321 if(activeChannel) {
322 if((sccp_strequals(iPbx.getChannelLinkedId(activeChannel), iPbx.getChannelLinkedId(c)))) {
323 sccp_log(DEBUGCAT_INDICATE)(VERBOSE_PREFIX_3 "%s: (SCCP_CHANNELSTATE_CALLWAITING) Already Own Part of the Call: Skipping\n", DEV_ID_LOG(d));
324 sccp_log_and(DEBUGCAT_INDICATE + DEBUGCAT_HIGH)(VERBOSE_PREFIX_3 "%s: LinkedId: %s / %s: LinkedId Remote: %s\n", DEV_ID_LOG(d), iPbx.getChannelLinkedId(c), DEV_ID_LOG(d),
325 iPbx.getChannelLinkedId(activeChannel));
326 break;
327 }
328 c->setTone(activeChannel, GLOB(callwaiting_tone), SKINNY_TONEDIRECTION_USER);
329 }
330 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_3 "%s: SCCP_CHANNELSTATE_CALLWAITING (%s)\n", DEV_ID_LOG(d), sccp_channelstate2str(c->previousChannelState));
331 // sccp_channel_callwaiting_tone_interval(d, c);
332 // c->setTone(c, GLOB(callwaiting_tone), SKINNY_TONEDIRECTION_USER);
333 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_RINGIN, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
334 iCallInfo.Send(ci, c->callid, c->calltype, lineInstance, d, TRUE);
335 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_CALL_WAITING, GLOB(digittimeout));
336 sccp_dev_set_ringer(d, SKINNY_RINGTYPE_SILENT, SKINNY_RINGDURATION_SINGLE, lineInstance, c->callid);
337 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_RINGIN);
338
339 #ifdef CS_SCCP_CONFERENCE
340 if (d->conferencelist_active) {
341 sccp_conference_hide_list_ByDevice(d);
342 }
343 #endif
344 }
345 break;
346 case SCCP_CHANNELSTATE_CALLPARK:
347 {
348 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_CALLPARK, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
349 }
350 break;
351 case SCCP_CHANNELSTATE_CALLTRANSFER:
352 {
353 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_TRANSFER, GLOB(digittimeout));
354 sccp_dev_set_ringer(d, SKINNY_RINGTYPE_OFF, SKINNY_RINGDURATION_NORMAL, lineInstance, c->callid);
355 sccp_device_sendcallstate(d, lineInstance, c->callid, SKINNY_CALLSTATE_CALLTRANSFER, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
356 iCallInfo.Send(ci, c->callid, c->calltype, lineInstance, d, FALSE);
357 }
358 break;
359 case SCCP_CHANNELSTATE_BLINDTRANSFER: // \todo SCCP_CHANNELSTATE_BLINDTRANSFER To be implemented
360 {
361 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_3 "%s: SCCP_CHANNELSTATE_BLINDTRANSFER (%s)\n", d->id, sccp_channelstate2str(c->previousChannelState));
362 }
363 break;
364 case SCCP_CHANNELSTATE_CALLCONFERENCE:
365 {
366 // sccp_device_sendcallstate(d, lineInstance, c->callid, SCCP_CHANNELSTATE_CALLCONFERENCE, SKINNY_CALLPRIORITY_LOW, SKINNY_CALLINFO_VISIBILITY_DEFAULT);
367 }
368 break;
369 case SCCP_CHANNELSTATE_CONNECTEDCONFERENCE:
370 {
371 d->indicate->connected(d, lineInstance, c->callid, c->calltype, ci);
372 sccp_rtp_setCallback(&c->rtp.audio, SCCP_RTP_RECEPTION, sccp_channel_startMediaTransmission);
373 if(!sccp_rtp_getState(&c->rtp.audio, SCCP_RTP_RECEPTION)) {
374 sccp_channel_openReceiveChannel(c);
375 } else if(!sccp_rtp_getState(&c->rtp.audio, SCCP_RTP_TRANSMISSION)) {
376 sccp_rtp_runCallback(&c->rtp.audio, SCCP_RTP_TRANSMISSION, c);
377 } else {
378 sccp_rtp_setCallback(&c->rtp.audio, SCCP_RTP_RECEPTION, NULL);
379 }
380 sccp_dev_set_keyset(d, lineInstance, c->callid, KEYMODE_CONNCONF);
381 }
382 break;
383 case SCCP_CHANNELSTATE_INVALIDCONFERENCE:
384 {
385 /*! \todo SCCP_CHANNELSTATE_INVALIDCONFERENCE To be implemented */
386 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_3 "%s: SCCP_CHANNELSTATE_INVALIDCONFERENCE (%s)\n", d->id, sccp_channelstate2str(c->previousChannelState));
387 }
388 break;
389 case SCCP_CHANNELSTATE_INVALIDNUMBER:
390 {
391 /* this is for the earlyrtp. The 7910 does not play tones if a rtp stream is open */
392 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_UNKNOWN_NUMBER, GLOB(digittimeout));
393 sccp_channel_closeAllMediaTransmitAndReceive(c);
394 c->setTone(c, SKINNY_TONE_REORDERTONE, SKINNY_TONEDIRECTION_USER);
395 sccp_channel_schedule_hangup(c, SCCP_HANGUP_TIMEOUT); // wait 15 seconds, then hangup automatically
396 }
397 break;
398 case SCCP_CHANNELSTATE_CONGESTION:
399 {
400 if(!sccp_rtp_getState(&c->rtp.audio, SCCP_RTP_RECEPTION)) {
401 /* congestion will be emulated if the rtp audio stream is not yet open */
402 c->setTone(c, SKINNY_TONE_REORDERTONE, SKINNY_TONEDIRECTION_USER);
403 }
404 iCallInfo.Send(ci, c->callid, c->calltype, lineInstance, d, FALSE);
405 sccp_dev_displayprompt(d, lineInstance, c->callid, SKINNY_DISP_TEMP_FAIL, GLOB(digittimeout));
406 sccp_channel_schedule_hangup(c, SCCP_HANGUP_TIMEOUT); // wait 15 seconds, then hangup automatically
407 }
408 break;
409 case SCCP_CHANNELSTATE_ONHOOK:
410 {
411 c->state = SCCP_CHANNELSTATE_DOWN;
412 if (c->answered_elsewhere && d->indicate->callhistory) {
413 iCallInfo.Send(ci, c->callid, c->calltype, lineInstance, d, TRUE);
414 d->indicate->callhistory(d, lineInstance, c->callid, d->callhistory_answered_elsewhere);
415 }
416 if (d->indicate && d->indicate->onhook) {
417 d->indicate->onhook(d, lineInstance, c->callid);
418 }
419 }
420 break;
421 default: //! \todo SCCP_CHANNELSTATE:default To be implemented
422 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_3 "%s: SCCP_CHANNELSTATE:default %s (%d) -> %s (%d)\n", d->id, sccp_channelstate2str(c->previousChannelState), c->previousChannelState, sccp_channelstate2str(c->state), c->state);
423 break;
424 }
425
426 /* if channel state has changed, notify the others */
427 if (d && (c->state != c->previousChannelState || force)) {
428 /* if it is a shared line and a state of interest */
429 if ((SCCP_RWLIST_GETSIZE (&l->devices) > 1) && !c->conference
430 && (c->state == SCCP_CHANNELSTATE_OFFHOOK || c->state == SCCP_CHANNELSTATE_DOWN || c->state == SCCP_CHANNELSTATE_ONHOOK || c->state == SCCP_CHANNELSTATE_CONNECTED
431 || c->state == SCCP_CHANNELSTATE_CONNECTEDCONFERENCE || c->state == SCCP_CHANNELSTATE_HOLD || c->state == SCCP_CHANNELSTATE_CALLPARK)) {
432 /* notify all remote devices */
433 __sccp_indicate_remote_device(d, c, l, state);
434 }
435
436 /* notify features (sccp_feat_channelstateChanged = empty function, skipping) */
437 // sccp_feat_channelstateChanged(d, c);
438 // sccp_log((DEBUGCAT_INDICATE + DEBUGCAT_CHANNEL)) (VERBOSE_PREFIX_4 "%s (sccp_indicate) Sending LineStatus Changed Event to State: %s(%d)\n", c->designator, sccp_channelstate2str(c->state), c->state);
439 sccp_event_t *event = sccp_event_allocate(SCCP_EVENT_LINESTATUS_CHANGED);
440 if (event) {
441 event->lineStatusChanged.line = sccp_line_retain(l);
442 event->lineStatusChanged.optional_device = sccp_device_retain(d);
443 event->lineStatusChanged.state = c->state;
444 sccp_event_fire(event);
445 }
446 }
447
448 sccp_log((DEBUGCAT_INDICATE + DEBUGCAT_CHANNEL)) (VERBOSE_PREFIX_3 "%s: Finish to indicate channel state:%s on call:%s, lineInstance:%d. New channel state:%s\n", d->id, sccp_channelstate2str(state), c->designator, lineInstance, sccp_channelstate2str(c->state));
449 //sccp_do_backtrace();
450 }
451
452 /*!
453 * \brief Indicate to Remote Device
454 * \param device SCCP Device
455 * \param c SCCP Channel
456 * \param line SCCP Line
457 * \param state State as int
458 *
459 * \warning
460 * - line->devices is not always locked
461 */
__sccp_indicate_remote_device(constDevicePtr device,channelPtr c,linePtr line,const sccp_channelstate_t state)462 static void __sccp_indicate_remote_device(constDevicePtr device, channelPtr c, linePtr line, const sccp_channelstate_t state)
463 {
464 int lineInstance = 0;
465
466 if (!c || !line) {
467 return;
468 }
469
470 /** \todo move this to channel->privacy */
471
472 /* do not propagate status of hotline */
473 if (line == GLOB(hotline)->line) {
474 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_3 "SCCP: (__sccp_indicate_remote_device) I'm a hotline, do not notify me!\n");
475 return;
476 }
477 sccp_linedevice_t * ld = NULL;
478
479 /* copy temp variables, information to be send to remote device (in another thread) */
480 const uint32_t callid = c->callid;
481 const skinny_calltype_t calltype = c->calltype;
482 char dialedNumber[SCCP_MAX_EXTENSION];
483 sccp_copy_string(dialedNumber, c->dialedNumber, SCCP_MAX_EXTENSION);
484 sccp_callinfo_t * ci = iCallInfo.CopyConstructor(sccp_channel_getCallInfo(c));
485
486 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_3 "%s: Remote Indicate state %s (%d) with reason: %s (%d) on remote devices for channel %s\n", DEV_ID_LOG(device), sccp_channelstate2str(state), state, sccp_channelstatereason2str(c->channelStateReason), c->channelStateReason, c->designator);
487 SCCP_LIST_TRAVERSE(&line->devices, ld, list) {
488 if(!ld->device) {
489 pbx_log(LOG_NOTICE, "Strange to find a ld (%p) here without a valid device connected to it !", ld);
490 continue;
491 }
492
493 if(ld->device == device) {
494 // skip self
495 continue;
496 }
497
498 /* check if we have one part of the remote channel */
499 AUTO_RELEASE(sccp_device_t, remoteDevice, sccp_device_retain(ld->device));
500
501 if (remoteDevice) {
502 sccp_callerid_presentation_t presenceParameter = CALLERID_PRESENTATION_ALLOWED;
503 iCallInfo.Getter(ci, SCCP_CALLINFO_PRESENTATION, &presenceParameter, SCCP_CALLINFO_KEY_SENTINEL);
504 skinny_callinfo_visibility_t stateVisibility = (c->privacy || !presenceParameter) ? SKINNY_CALLINFO_VISIBILITY_HIDDEN : SKINNY_CALLINFO_VISIBILITY_DEFAULT;
505
506 /* Remarking the next piece out, solves the transfer issue when using sharedline as default on the transferer. Don't know why though (yet) */
507 if (state != SCCP_CHANNELSTATE_ONHOOK) {
508 AUTO_RELEASE(sccp_channel_t, activeChannel , sccp_device_getActiveChannel(remoteDevice));
509
510 if (activeChannel && (sccp_strequals(iPbx.getChannelLinkedId(activeChannel), iPbx.getChannelLinkedId(c)) || (activeChannel->conference_id && activeChannel->conference_id == c->conference_id))) {
511 sccp_log(DEBUGCAT_INDICATE) (VERBOSE_PREFIX_3 "%s: (indicate_remote_device) Already Own Part of the Call: Skipped\n", DEV_ID_LOG(device));
512 //sccp_log_and(DEBUGCAT_INDICATE + DEBUGCAT_HIGH) (VERBOSE_PREFIX_3 "%s: LinkedId: %s / %s: LinkedId Remote: %s\n", DEV_ID_LOG(device), iPbx.getChannelLinkedId(c), DEV_ID_LOG(remoteDevice), iPbx.getChannelLinkedId(activeChannel));
513 continue;
514 }
515 }
516
517 if(ld) {
518 lineInstance = ld->lineInstance; // sccp_device_find_index_for_line(remoteDevice, line->name);
519 }
520 switch (state) {
521 case SCCP_CHANNELSTATE_DOWN:
522 case SCCP_CHANNELSTATE_ONHOOK:
523 sccp_log(DEBUGCAT_INDICATE) (VERBOSE_PREFIX_3 "%s -> %s: indicate remote onhook (lineInstance: %d, callid: %d %s)\n", DEV_ID_LOG(device), DEV_ID_LOG(remoteDevice), lineInstance, c->callid, c->answered_elsewhere ? ", answered elsewhere" :"");
524 if (SKINNY_CALLTYPE_INBOUND == c->calltype && c->answered_elsewhere && remoteDevice->indicate->callhistory) {
525 remoteDevice->indicate->callhistory(remoteDevice, lineInstance, c->callid, remoteDevice->callhistory_answered_elsewhere);
526 }
527 remoteDevice->indicate->remoteOnhook(remoteDevice, lineInstance, callid);
528 break;
529
530 case SCCP_CHANNELSTATE_CONNECTEDCONFERENCE:
531 case SCCP_CHANNELSTATE_CONNECTED:
532 sccp_log(DEBUGCAT_INDICATE) (VERBOSE_PREFIX_3 "%s -> %s: indicate remote connected (lineInstance: %d, callid: %d %s)\n", DEV_ID_LOG(device), DEV_ID_LOG(remoteDevice), lineInstance, c->callid, c->answered_elsewhere ? ", answered elsewhere" : "");
533 if (SKINNY_CALLTYPE_INBOUND == c->calltype && remoteDevice->indicate->callhistory) {
534 //remoteDevice->indicate->callhistory(remoteDevice, lineInstance, c->callid, remoteDevice->callhistory_answered_elsewhere);
535 remoteDevice->indicate->callhistory(remoteDevice, lineInstance, c->callid, SKINNY_CALL_HISTORY_DISPOSITION_IGNORE);
536 }
537
538 /* if line is not currently active on remote device, collapse the callstate */
539 // if (remoteDevice->currentLine && ld->line != remoteDevice->currentLine && !(c->privacy || !presenceParameter)) {
540 if((c->privacy || presenceParameter == CALLERID_PRESENTATION_FORBIDDEN)
541 || (!sccp_softkey_isSoftkeyInSoftkeySet(remoteDevice, KEYMODE_ONHOOKSTEALABLE, SKINNY_LBL_INTRCPT)
542 && !sccp_softkey_isSoftkeyInSoftkeySet(remoteDevice, KEYMODE_ONHOOKSTEALABLE, SKINNY_LBL_BARGE))) {
543 stateVisibility = SKINNY_CALLINFO_VISIBILITY_COLLAPSED;
544 }
545 if (c->channelStateReason == SCCP_CHANNELSTATEREASON_BARGE || c->isBarging || c->isBarged) {
546 stateVisibility = SKINNY_CALLINFO_VISIBILITY_HIDDEN;
547 }
548 remoteDevice->indicate->remoteConnected(remoteDevice, lineInstance, callid, stateVisibility);
549 iCallInfo.Send(ci, callid, calltype, lineInstance, remoteDevice, TRUE);
550 break;
551
552 case SCCP_CHANNELSTATE_HOLD:
553 if (c->channelStateReason == SCCP_CHANNELSTATEREASON_NORMAL) {
554 remoteDevice->indicate->remoteHold(remoteDevice, lineInstance, callid, SKINNY_CALLPRIORITY_NORMAL, stateVisibility);
555 iCallInfo.Send(ci, callid, calltype, lineInstance, remoteDevice, TRUE);
556 } else {
557 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_3 "%s: Skipped Remote Hold Indication for reason: %s\n", DEV_ID_LOG(device), sccp_channelstatereason2str(c->channelStateReason));
558 }
559 break;
560
561 case SCCP_CHANNELSTATE_CALLPARK:
562 if (c->channelStateReason == SCCP_CHANNELSTATEREASON_NORMAL) {
563 remoteDevice->indicate->remoteHold (remoteDevice, lineInstance, callid, SKINNY_CALLPRIORITY_NORMAL, stateVisibility);
564 iCallInfo.Send (ci, callid, calltype, lineInstance, remoteDevice, TRUE);
565 }
566 default:
567 break;
568
569 }
570 sccp_log((DEBUGCAT_INDICATE)) (VERBOSE_PREFIX_3 "%s: Finish Indicating state %s (%d) with reason: %s (%d) on remote device %s for channel %s\n", DEV_ID_LOG(device), sccp_channelstate2str(state), state, sccp_channelstatereason2str(c->channelStateReason), c->channelStateReason, DEV_ID_LOG(remoteDevice), c->designator);
571 }
572 }
573 iCallInfo.Destructor(&ci);
574 }
575
576 // 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;
577