1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** all actions (and hangup) are processed here **
10 \*****************************************************************************/
14 extern char **environ;
18 * process init 'internal' / 'external' / 'remote' / 'vbox-record' / 'partyline'...
20 int EndpointAppPBX::_action_init_call(char *remote)
23 struct port_list *portlist = ea_endpoint->ep_portlist;
24 struct admin_list *admin;
26 /* a created call, this should never happen */
27 if (ea_endpoint->ep_join_id) {
28 if (options.deb & DEBUG_EPOINT)
29 PERROR("EPOINT(%d): We already have a call instance, this should never happen!\n", ea_endpoint->ep_serial);
34 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new join instance.\n", ea_endpoint->ep_serial);
38 if (admin->remote_name[0] && !strcmp(admin->remote_name, remote))
43 /* resource not available */
44 trace_header("ACTION remote (not available)", DIRECTION_NONE);
45 add_trace("application", NULL, "%s", remote);
47 message_disconnect_port(portlist, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, "");
48 new_state(EPOINT_STATE_OUT_DISCONNECT);
49 set_tone(portlist,"cause_1b");
52 join = new JoinRemote(ea_endpoint->ep_serial, remote, admin->sock);
55 join = new JoinPBX(ea_endpoint);
57 FATAL("No memoy for Join instance.\n");
58 ea_endpoint->ep_join_id = join->j_serial;
61 void EndpointAppPBX::action_init_call(void)
63 _action_init_call(NULL);
65 void EndpointAppPBX::action_init_remote(void)
70 * process dialing 'internal'
72 void EndpointAppPBX::action_dialing_internal(void)
74 struct capa_info capainfo;
75 struct caller_info callerinfo;
76 struct redir_info redirinfo;
77 struct dialing_info dialinginfo;
78 struct port_list *portlist = ea_endpoint->ep_portlist;
79 struct lcr_msg *message;
81 struct route_param *rparam;
83 /* send proceeding, because number is complete */
84 set_tone(portlist, "proceeding");
85 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
87 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
88 new_state(EPOINT_STATE_IN_PROCEEDING);
90 /* create bearer/caller/dialinginfo */
91 memcpy(&capainfo, &e_capainfo, sizeof(capainfo));
92 memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo));
93 memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo));
94 memset(&dialinginfo, 0, sizeof(dialinginfo));
95 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
96 SCPY(dialinginfo.id, e_dialinginfo.id);
98 /* process extension */
99 if ((rparam = routeparam(e_action, PARAM_EXTENSION)))
100 SCPY(dialinginfo.id, rparam->string_value);
102 /* process number type */
103 if ((rparam = routeparam(e_action, PARAM_TYPE)))
104 dialinginfo.ntype = rparam->integer_value;
106 /* process service */
107 if ((rparam = routeparam(e_action, PARAM_CAPA))) {
108 capainfo.bearer_capa = rparam->integer_value;
109 if (capainfo.bearer_capa != INFO_BC_SPEECH
110 && capainfo.bearer_capa != INFO_BC_AUDIO) {
111 capainfo.bearer_mode = INFO_BMODE_PACKET;
113 capainfo.bearer_info1 = INFO_INFO1_NONE;
115 if ((rparam = routeparam(e_action, PARAM_BMODE))) {
116 capainfo.bearer_mode = rparam->integer_value;
118 if ((rparam = routeparam(e_action, PARAM_INFO1))) {
119 capainfo.bearer_info1 = rparam->integer_value;
121 if ((rparam = routeparam(e_action, PARAM_HLC))) {
122 capainfo.hlc = rparam->integer_value;
124 if ((rparam = routeparam(e_action, PARAM_EXTHLC))) {
125 capainfo.exthlc = rparam->integer_value;
128 /* process presentation */
129 if ((rparam = routeparam(e_action, PARAM_PRESENT))) {
130 callerinfo.present = (rparam->integer_value)?INFO_PRESENT_ALLOWED:INFO_PRESENT_RESTRICTED;
133 /* check if extension exists AND only if not multiple extensions */
134 if (!strchr(dialinginfo.id,',') && !read_extension(&ext, dialinginfo.id)) {
135 trace_header("ACTION extension (extension doesn't exist)", DIRECTION_NONE);
136 add_trace("extension", NULL, dialinginfo.id);
138 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0);
139 new_state(EPOINT_STATE_OUT_DISCONNECT);
140 message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
141 set_tone(portlist, "cause_86");
144 /* check if internal calls are denied */
145 if (e_ext.rights < 1) {
146 trace_header("ACTION extension (dialing to extension denied)", DIRECTION_NONE);
147 add_trace("extension", NULL, dialinginfo.id);
149 new_state(EPOINT_STATE_OUT_DISCONNECT);
150 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0);
151 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
152 set_tone(portlist, "cause_81");
156 /* add or update internal call */
157 trace_header("ACTION extension (calling)", DIRECTION_NONE);
158 add_trace("extension", NULL, dialinginfo.id);
160 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
161 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
162 memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
163 memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
164 memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info));
165 message_put(message);
168 /* process dialing external
170 void EndpointAppPBX::action_dialing_external(void)
172 struct capa_info capainfo;
173 struct caller_info callerinfo;
174 struct redir_info redirinfo;
175 struct dialing_info dialinginfo;
177 struct port_list *portlist = ea_endpoint->ep_portlist;
178 struct lcr_msg *message;
179 struct route_param *rparam;
181 /* special processing of delete characters '*' and '#' */
182 if (e_ext.delete_ext) {
183 /* dialing a # causes a clearing of complete number */
184 if (strchr(e_extdialing, '#')) {
185 e_extdialing[0] = '\0';
186 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): '#' detected: terminal '%s' selected caller id '%s' and continues dialing: '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, e_extdialing);
188 /* eliminate digits before '*', which is a delete digit
190 if (strchr(e_extdialing, '*')) {
192 while((p=strchr(e_extdialing, '*'))) {
193 if (p > e_extdialing) { /* only if there is a digit in front */
197 UCPY(p, p+1); /* remove '*' */
199 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s deleted digits and got new string: %s\n", ea_endpoint->ep_serial, e_ext.number, e_extdialing);
203 /* create bearer/caller/dialinginfo */
204 memcpy(&capainfo, &e_capainfo, sizeof(capainfo));
205 memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo));
206 memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo));
207 memset(&dialinginfo, 0, sizeof(dialinginfo));
208 dialinginfo.itype = INFO_ITYPE_ISDN;
209 dialinginfo.sending_complete = 0;
210 SCPY(dialinginfo.id, e_extdialing);
213 if ((rparam = routeparam(e_action, PARAM_PREFIX)))
214 SPRINT(dialinginfo.id, "%s%s", rparam->string_value, e_extdialing);
217 if ((rparam = routeparam(e_action, PARAM_KEYPAD))) {
218 SCPY(dialinginfo.keypad, dialinginfo.id);
219 dialinginfo.id[0] = '\0';
222 /* process number complete */
223 if ((rparam = routeparam(e_action, PARAM_COMPLETE)))
224 if ((rparam = routeparam(e_action, PARAM_PREFIX)))
225 SCPY(dialinginfo.id, rparam->string_value);
226 dialinginfo.sending_complete = 1;
228 /* process number type */
229 if ((rparam = routeparam(e_action, PARAM_TYPE)))
230 dialinginfo.ntype = rparam->integer_value;
232 /* process service */
233 if ((rparam = routeparam(e_action, PARAM_CAPA))) {
234 capainfo.bearer_capa = rparam->integer_value;
235 if (capainfo.bearer_capa != INFO_BC_SPEECH
236 && capainfo.bearer_capa != INFO_BC_AUDIO) {
237 capainfo.bearer_mode = INFO_BMODE_PACKET;
239 capainfo.bearer_info1 = INFO_INFO1_NONE;
241 if ((rparam = routeparam(e_action, PARAM_BMODE))) {
242 capainfo.bearer_mode = rparam->integer_value;
244 if ((rparam = routeparam(e_action, PARAM_INFO1))) {
245 capainfo.bearer_info1 = rparam->integer_value;
247 if ((rparam = routeparam(e_action, PARAM_HLC))) {
248 capainfo.hlc = rparam->integer_value;
250 if ((rparam = routeparam(e_action, PARAM_EXTHLC))) {
251 capainfo.exthlc = rparam->integer_value;
255 /* process callerid */
256 if ((rparam = routeparam(e_action, PARAM_CALLERID))) {
257 SCPY(callerinfo.id, rparam->string_value);
259 if ((rparam = routeparam(e_action, PARAM_CALLERIDTYPE))) {
260 callerinfo.ntype = rparam->integer_value;
263 /* process presentation */
264 if ((rparam = routeparam(e_action, PARAM_PRESENT))) {
265 callerinfo.present = (rparam->integer_value)?INFO_PRESENT_ALLOWED:INFO_PRESENT_RESTRICTED;
268 /* process interfaces */
269 if ((rparam = routeparam(e_action, PARAM_INTERFACES)))
270 SCPY(dialinginfo.interfaces, rparam->string_value);
272 /* check if local calls are denied */
273 if (e_ext.rights < 2) {
274 trace_header("ACTION extern (calling denied)", DIRECTION_NONE);
276 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0);
277 set_tone(portlist, "cause_82");
279 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
280 new_state(EPOINT_STATE_OUT_DISCONNECT);
284 if (!strncmp(dialinginfo.id, options.national, strlen(options.national))
285 || dialinginfo.ntype == INFO_NTYPE_NATIONAL
286 || dialinginfo.ntype == INFO_NTYPE_INTERNATIONAL) {
287 /* check if national calls are denied */
288 if (e_ext.rights < 3) {
289 trace_header("ACTION extern (national calls denied)", DIRECTION_NONE);
291 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0);
292 set_tone(portlist, "cause_83");
297 if (!strncmp(dialinginfo.id, options.international, strlen(options.international))
298 || dialinginfo.ntype == INFO_NTYPE_INTERNATIONAL) {
299 /* check if international calls are denied */
300 if (e_ext.rights < 4) {
301 trace_header("ACTION extern (international calls denied)", DIRECTION_NONE);
303 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_REJECTED, 0, 0, 0);
304 set_tone(portlist, "cause_84");
309 /* add or update outgoing call */
310 trace_header("ACTION extern (calling)", DIRECTION_NONE);
311 add_trace("number", NULL, dialinginfo.id);
312 if (dialinginfo.interfaces[0])
313 add_trace("interfaces", NULL, dialinginfo.interfaces);
315 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
316 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
317 memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
318 memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
319 memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info));
320 message_put(message);
324 void EndpointAppPBX::action_dialing_remote(void)
326 struct route_param *rparam;
327 struct port_list *portlist = ea_endpoint->ep_portlist;
328 struct lcr_msg *message;
329 struct capa_info capainfo;
330 struct caller_info callerinfo;
331 struct redir_info redirinfo;
332 struct dialing_info dialinginfo;
333 char context[128] = "";
336 if (!ea_endpoint->ep_join_id) {
337 /* no join yet, sending setup */
338 if (!(rparam = routeparam(e_action, PARAM_APPLICATION))) {
339 trace_header("ACTION remote (no application given)", DIRECTION_NONE);
341 new_state(EPOINT_STATE_OUT_DISCONNECT);
342 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
343 set_tone(portlist, "cause_3f");
346 SCPY(remote, rparam->string_value);
347 if (!_action_init_call(remote))
350 /* create bearer/caller/dialinginfo */
351 memcpy(&capainfo, &e_capainfo, sizeof(capainfo));
352 memcpy(&callerinfo, &e_callerinfo, sizeof(callerinfo));
353 memcpy(&redirinfo, &e_redirinfo, sizeof(redirinfo));
354 memset(&dialinginfo, 0, sizeof(dialinginfo));
356 if ((rparam = routeparam(e_action, PARAM_CONTEXT))) {
357 SCPY(context, rparam->string_value);
359 if ((rparam = routeparam(e_action, PARAM_EXTEN))) {
360 SCPY(dialinginfo.id, rparam->string_value);
361 dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
363 SCPY(dialinginfo.id, e_extdialing);
365 e_extdialing = e_dialinginfo.id + strlen(e_dialinginfo.id);
366 /* send setup to remote */
367 trace_header("ACTION remote (setup)", DIRECTION_NONE);
368 add_trace("number", NULL, dialinginfo.id);
369 add_trace("remote", NULL, remote);
371 add_trace("context", NULL, context);
373 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
374 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
375 memcpy(&message->param.setup.redirinfo, &redirinfo, sizeof(struct redir_info));
376 memcpy(&message->param.setup.callerinfo, &callerinfo, sizeof(struct caller_info));
377 memcpy(&message->param.setup.capainfo, &capainfo, sizeof(struct capa_info));
378 SCPY(message->param.setup.context, context);
379 message_put(message);
381 /* send overlap digits */
382 trace_header("ACTION remote (dialing)", DIRECTION_NONE);
383 add_trace("number", NULL, e_extdialing);
385 if (e_extdialing[0]) {
386 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_INFORMATION);
387 memcpy(&message->param.information, &e_dialinginfo, sizeof(struct dialing_info));
388 SCPY(message->param.information.id, e_extdialing);
389 e_extdialing = e_dialinginfo.id + strlen(e_dialinginfo.id);
390 message_put(message);
397 * process dialing the "am" and record
399 void EndpointAppPBX::action_dialing_vbox_record(void)
401 struct dialing_info dialinginfo;
402 struct port_list *portlist = ea_endpoint->ep_portlist;
403 struct lcr_msg *message;
404 struct extension ext;
405 struct route_param *rparam;
407 portlist = ea_endpoint->ep_portlist;
409 /* check for given extension */
410 if (!(rparam = routeparam(e_action, PARAM_EXTENSION))) {
411 trace_header("ACTION vbox-record (no extension given by parameter)", DIRECTION_NONE);
414 new_state(EPOINT_STATE_OUT_DISCONNECT);
415 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
416 set_tone(portlist, "cause_3f");
420 /* check if extension exists */
421 if (!read_extension(&ext, rparam->string_value)) {
422 trace_header("ACTION vbox-record (given extension does not exists)", DIRECTION_NONE);
423 add_trace("extension", NULL, "%s", rparam->string_value);
425 new_state(EPOINT_STATE_OUT_DISCONNECT);
426 message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
427 set_tone(portlist, "cause_86");
431 /* check if internal calls are denied */
432 if (e_ext.rights < 1) {
433 trace_header("ACTION vbox-record (internal calls are denied)", DIRECTION_NONE);
435 new_state(EPOINT_STATE_OUT_DISCONNECT);
436 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
437 set_tone(portlist, "cause_81");
441 set_tone(portlist, "proceeding");
442 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
443 message_put(message);
444 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
445 new_state(EPOINT_STATE_IN_PROCEEDING);
447 memset(&dialinginfo, 0, sizeof(dialinginfo));
448 dialinginfo.itype = INFO_ITYPE_VBOX;
449 dialinginfo.sending_complete = 1;
450 SCPY(dialinginfo.id, rparam->string_value);
452 /* append special announcement (if given) */
453 if ((rparam = routeparam(e_action, PARAM_ANNOUNCEMENT)))
454 if (rparam->string_value[0]) {
455 SCAT(dialinginfo.id, ",");
456 SCAT(dialinginfo.id, rparam->string_value);
459 /* add or update internal call */
460 trace_header("ACTION vbox-record (calling)", DIRECTION_NONE);
461 add_trace("extension", NULL, "%s", dialinginfo.id);
463 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
464 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
465 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
466 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
467 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
468 message_put(message);
475 void EndpointAppPBX::action_init_partyline(void)
478 class JoinPBX *joinpbx;
479 struct port_list *portlist = ea_endpoint->ep_portlist;
480 struct lcr_msg *message;
481 struct route_param *rparam;
482 int partyline, jingle = 0;
483 struct join_relation *relation;
485 portlist = ea_endpoint->ep_portlist;
487 /* check for given extension */
488 if (!(rparam = routeparam(e_action, PARAM_ROOM))) {
489 trace_header("ACTION partyline (no room parameter)", DIRECTION_NONE);
492 new_state(EPOINT_STATE_OUT_DISCONNECT);
493 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
494 set_tone(portlist, "cause_3f");
497 if (rparam->integer_value <= 0) {
498 trace_header("ACTION partyline (illegal room parameter)", DIRECTION_NONE);
499 add_trace("room", NULL, "%d", rparam->integer_value);
501 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): invalid value for 'room'.\n", ea_endpoint->ep_serial);
504 partyline = rparam->integer_value;
505 if ((rparam = routeparam(e_action, PARAM_JINGLE)))
508 /* don't create join if partyline exists */
511 if (join->j_type == JOIN_TYPE_PBX) {
512 joinpbx = (class JoinPBX *)join;
513 if (joinpbx->j_partyline == partyline)
520 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): Creating new join instance.\n", ea_endpoint->ep_serial);
521 if (!(join = new JoinPBX(ea_endpoint)))
522 FATAL("No memory for join object\n");
524 //NOTE: joinpbx must be set here
525 /* add relation to existing join */
526 if (!(relation=joinpbx->add_relation()))
527 FATAL("No memory for join relation\n");
528 relation->type = RELATION_TYPE_SETUP;
529 relation->channel_state = 1;
530 relation->rx_state = NOTIFY_STATE_ACTIVE;
531 relation->tx_state = NOTIFY_STATE_ACTIVE;
532 relation->epoint_id = ea_endpoint->ep_serial;
535 ea_endpoint->ep_join_id = join->j_serial;
537 set_tone(portlist, "proceeding");
538 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
539 message_put(message);
540 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
541 new_state(EPOINT_STATE_IN_PROCEEDING);
543 /* send setup to join */
544 trace_header("ACTION partyline (calling)", DIRECTION_NONE);
545 add_trace("room", NULL, "%d", partyline);
546 add_trace("jingle", NULL, (jingle)?"on":"off");
548 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_SETUP);
549 message->param.setup.partyline = partyline;
550 message->param.setup.partyline_jingle = jingle;
551 memcpy(&message->param.setup.dialinginfo, &e_dialinginfo, sizeof(struct dialing_info));
552 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
553 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
554 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
555 message_put(message);
560 * process hangup of all calls
562 void EndpointAppPBX::action_hangup_call(void)
564 trace_header("ACTION hangup", DIRECTION_NONE);
570 * process dialing 'login'
572 void EndpointAppPBX::action_dialing_login(void)
574 struct port_list *portlist = ea_endpoint->ep_portlist;
575 struct lcr_msg *message;
577 struct route_param *rparam;
579 /* extension parameter */
580 if ((rparam = routeparam(e_action, PARAM_EXTENSION))) {
581 /* extension is given by parameter */
582 extension = rparam->string_value;
583 if (extension[0] == '\0')
585 if (!read_extension(&e_ext, extension)) {
586 trace_header("ACTION login (extension doesn't exist)", DIRECTION_NONE);
587 add_trace("extension", NULL, "%s", extension);
589 /* extension doesn't exist */
590 new_state(EPOINT_STATE_OUT_DISCONNECT);
591 message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
592 set_tone(portlist, "cause_86");
596 /* extension must be given by dialstring */
597 extension = e_extdialing;
598 if (extension[0] == '\0')
600 if (!read_extension(&e_ext, extension)) {
601 trace_header("ACTION login (extension incomplete or does not exist)", DIRECTION_NONE);
602 add_trace("extension", NULL, "%s", extension);
608 /* we changed our extension */
609 SCPY(e_ext.number, extension);
610 new_state(EPOINT_STATE_CONNECT);
614 /* send connect with extension's caller id (COLP) */
615 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
616 SCPY(message->param.connectinfo.id, e_ext.callerid);
617 message->param.connectinfo.ntype = e_ext.callerid_type;
618 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
619 message->param.connectinfo.present = INFO_PRESENT_RESTRICTED;
620 else message->param.connectinfo.present = e_ext.callerid_present;
621 /* handle restricted caller ids */
622 apply_callerid_restriction(&e_ext, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
623 /* display callerid if desired for extension */
624 SCPY(message->param.connectinfo.display, apply_callerid_display(message->param.connectinfo.id, message->param.connectinfo.itype, message->param.connectinfo.ntype, message->param.connectinfo.present, message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name));
625 message->param.connectinfo.ntype = e_ext.callerid_type;
626 message_put(message);
627 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
629 /* set our caller id */
630 SCPY(e_callerinfo.id, e_ext.callerid);
631 e_callerinfo.ntype = e_ext.callerid_type;
632 e_callerinfo.present = e_ext.callerid_present;
634 /* enable connectedmode */
638 if (!(rparam = routeparam(e_action, PARAM_NOPASSWORD))) {
639 /* make call state to enter password */
640 trace_header("ACTION login (ask for password)", DIRECTION_NONE);
641 add_trace("extension", NULL, "%s", e_ext.number);
643 new_state(EPOINT_STATE_IN_OVERLAP);
646 e_action = &action_password;
647 unsched_timer(&e_match_timeout);
648 e_match_to_action = NULL;
649 e_dialinginfo.id[0] = '\0';
650 e_extdialing = strchr(e_dialinginfo.id, '\0');
653 schedule_timer(&e_password_timeout, 20, 0);
658 /* make call state */
659 new_state(EPOINT_STATE_IN_OVERLAP);
660 e_ruleset = ruleset_main;
662 e_rule = e_ruleset->rule_first;
664 e_dialinginfo.id[0] = '\0';
665 e_extdialing = e_dialinginfo.id;
666 set_tone(portlist, "dialpbx");
672 * process init 'change_callerid'
674 void EndpointAppPBX::action_init_change_callerid(void)
676 struct port_list *portlist = ea_endpoint->ep_portlist;
678 if (!e_ext.change_callerid) {
679 /* service not available */
680 trace_header("ACTION change-callerid (denied for this caller)", DIRECTION_NONE);
682 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
683 new_state(EPOINT_STATE_OUT_DISCONNECT);
684 set_tone(portlist,"cause_87");
689 /* process dialing callerid
691 void EndpointAppPBX::_action_callerid_calleridnext(int next)
693 struct port_list *portlist = ea_endpoint->ep_portlist;
694 struct route_param *rparam;
695 char buffer[64], *callerid;
696 char old_id[64] = "", new_id[64] = "";
697 int old_type=0, new_type=0, old_present=0, new_present=0;
699 if ((rparam = routeparam(e_action, PARAM_CALLERID))) {
700 /* the caller ID is given by parameter */
701 callerid = rparam->string_value;
703 /* caller ID is dialed */
704 if (!strchr(e_extdialing, '#')) {
705 /* no complete ID yet */
708 *strchr(e_extdialing, '#') = '\0';
709 callerid = e_extdialing;
712 /* given callerid type */
713 if ((rparam = routeparam(e_action, PARAM_CALLERIDTYPE)))
714 switch(rparam->integer_value) {
715 case INFO_NTYPE_SUBSCRIBER:
716 SPRINT(buffer, "s%s", callerid);
719 case INFO_NTYPE_NATIONAL:
720 SPRINT(buffer, "n%s", callerid);
723 case INFO_NTYPE_INTERNATIONAL:
724 SPRINT(buffer, "i%s", callerid);
728 SPRINT(buffer, "%s", callerid);
733 /* caller id complete, dialing with new caller id */
734 /* write new parameters */
735 if (read_extension(&e_ext, e_ext.number)) {
736 old_present = (!next)?e_ext.callerid_present:e_ext.id_next_call_present;
737 old_type = (!next)?e_ext.callerid_type:e_ext.id_next_call_type;
738 SCPY(old_id, (!next)?e_ext.callerid:e_ext.id_next_call);
739 if (callerid[0] == '\0') {
741 (!next)?e_ext.callerid_present:e_ext.id_next_call_present = INFO_PRESENT_RESTRICTED;
744 (!next)?e_ext.callerid_present:e_ext.id_next_call_present = INFO_PRESENT_ALLOWED;
745 if ((rparam = routeparam(e_action, PARAM_PRESENT))) if (rparam->integer_value == 0)
746 (!next)?e_ext.callerid_present:e_ext.id_next_call_present = INFO_PRESENT_RESTRICTED;
747 if (e_ext.callerid_type == INFO_NTYPE_UNKNOWN) /* if callerid is unknown, the given id is not nationalized */ {
748 SCPY((!next)?e_ext.callerid:e_ext.id_next_call, callerid);
749 (!next)?e_ext.callerid_type:e_ext.id_next_call_type = INFO_NTYPE_UNKNOWN;
751 SCPY((!next)?e_ext.callerid:e_ext.id_next_call, nationalize_callerinfo(callerid,&((!next)?e_ext.callerid_type:e_ext.id_next_call_type), options.national, options.international));
753 if (!next) e_ext.id_next_call_type = -1;
754 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): nationalized callerid: '%s' type=%d\n", ea_endpoint->ep_serial, (!next)?e_ext.callerid:e_ext.id_next_call, (!next)?e_ext.callerid_type:e_ext.id_next_call_type);
756 new_present = (!next)?e_ext.callerid_present:e_ext.id_next_call_present;
757 new_type = (!next)?e_ext.callerid_type:e_ext.id_next_call_type;
758 SCPY(new_id, (!next)?e_ext.callerid:e_ext.id_next_call);
759 write_extension(&e_ext, e_ext.number);
762 /* function activated */
764 trace_header("ACTION change-callerid (only next call)", DIRECTION_NONE);
766 trace_header("ACTION change-callerid (all future calls)", DIRECTION_NONE);
767 add_trace("old", "caller id", "%s", numberrize_callerinfo(old_id, old_type, options.national, options.international));
768 add_trace("old", "present", "%s", (old_present==INFO_PRESENT_RESTRICTED)?"restricted":"allowed");
769 add_trace("new", "caller id", "%s", numberrize_callerinfo(new_id, new_type, options.national, options.international));
770 add_trace("new", "present", "%s", (new_present==INFO_PRESENT_RESTRICTED)?"restricted":"allowed");
772 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
773 new_state(EPOINT_STATE_OUT_DISCONNECT);
774 set_tone(portlist,"activated");
777 /* process dialing callerid for all call
779 void EndpointAppPBX::action_dialing_callerid(void)
781 _action_callerid_calleridnext(0);
784 /* process dialing callerid for next call
786 void EndpointAppPBX::action_dialing_calleridnext(void)
788 _action_callerid_calleridnext(1);
793 * process init 'change_forward'
795 void EndpointAppPBX::action_init_change_forward(void)
797 struct port_list *portlist = ea_endpoint->ep_portlist;
799 if (!e_ext.change_forward) {
800 trace_header("ACTION change-forward (denied for this caller)", DIRECTION_NONE);
802 /* service not available */
803 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
804 new_state(EPOINT_STATE_OUT_DISCONNECT);
805 set_tone(portlist,"cause_87");
810 /* process dialing forwarding
812 void EndpointAppPBX::action_dialing_forward(void)
814 struct port_list *portlist = ea_endpoint->ep_portlist;
815 int diversion = INFO_DIVERSION_CFU;
816 char *dest = e_extdialing;
817 struct route_param *rparam;
819 /* if diversion type is given */
820 if ((rparam = routeparam(e_action, PARAM_DIVERSION)))
821 diversion = rparam->integer_value;
823 if ((rparam = routeparam(e_action, PARAM_DEST))) {
824 /* if destination is given */
825 dest = rparam->string_value;
827 if (!strchr(e_extdialing, '#'))
829 *strchr(e_extdialing, '#') = '\0';
833 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing forwarding to '%s'.\n", ea_endpoint->ep_serial, e_ext.number, dest);
834 if (read_extension(&e_ext, e_ext.number)) {
836 case INFO_DIVERSION_CFU:
837 trace_header("ACTION change-forward (new CFU=unconditional)", DIRECTION_NONE);
838 add_trace("destin'", NULL, "%s", dest);
840 SCPY(e_ext.cfu, dest);
842 case INFO_DIVERSION_CFB:
843 trace_header("ACTION change-forward (new CFB=busy)", DIRECTION_NONE);
844 add_trace("destin'", NULL, "%s", dest);
846 SCPY(e_ext.cfb, dest);
848 case INFO_DIVERSION_CFNR:
849 if ((rparam = routeparam(e_action, PARAM_DELAY)))
850 e_ext.cfnr_delay = rparam->integer_value;
851 trace_header("ACTION change-forward (new CFNR=no response)", DIRECTION_NONE);
852 add_trace("destin'", NULL, "%s", dest);
853 add_trace("delay", NULL, "%s", e_ext.cfnr_delay);
855 SCPY(e_ext.cfnr, dest);
857 case INFO_DIVERSION_CFP:
858 trace_header("ACTION change-forward (new CFP=parallel)", DIRECTION_NONE);
859 add_trace("destin'", NULL, "%s", dest);
861 SCPY(e_ext.cfp, dest);
864 write_extension(&e_ext, e_ext.number);
866 /* function (de)activated */
867 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
868 new_state(EPOINT_STATE_OUT_DISCONNECT);
870 set_tone(portlist,"activated");
872 set_tone(portlist,"deactivated");
876 /* process dialing redial
878 void EndpointAppPBX::action_init_redial_reply(void)
880 struct port_list *portlist = ea_endpoint->ep_portlist;
883 if (!e_ext.last_out[0]) {
884 trace_header("ACTION redial/reply (no last number stored)", DIRECTION_NONE);
886 new_state(EPOINT_STATE_OUT_DISCONNECT);
887 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
888 set_tone(portlist, "cause_3f");
893 /* process dialing redial
895 void EndpointAppPBX::_action_redial_reply(int in)
897 struct lcr_msg *message;
899 struct route_param *rparam;
901 last = (in)?e_ext.last_in[0]:e_ext.last_out[0];
903 /* if no display is available */
904 if (!e_ext.display_menu)
906 if (ea_endpoint->ep_portlist->port_type!=PORT_TYPE_DSS1_NT_IN && ea_endpoint->ep_portlist->port_type!=PORT_TYPE_DSS1_NT_OUT)
909 /* if select is not given */
910 if (!(rparam = routeparam(e_action, PARAM_SELECT)))
914 if (e_extdialing[0]=='*' || e_extdialing[0]=='1') {
915 /* find prev entry */
921 if (e_extdialing[0]=='#' || e_extdialing[0]=='3') {
922 /* find next entry */
924 if (e_select >= MAX_REMEMBER) {
927 if (e_ext.last_in[e_select][0] == '\0')
930 if (e_ext.last_out[e_select][0] == '\0')
935 last = (in)?e_ext.last_in[e_select]:e_ext.last_out[e_select];
936 if (e_extdialing[0]=='0' || e_extdialing[0]=='2') {
939 trace_header("ACTION reply (dialing)", DIRECTION_NONE);
941 trace_header("ACTION redial (dialing)", DIRECTION_NONE);
942 add_trace("number", NULL, "%s", last);
943 add_trace("last but", NULL, "%d", e_select);
945 SCPY(e_dialinginfo.id, last);
946 e_extdialing = e_dialinginfo.id;
951 e_extdialing[0] = '\0';
953 /* send display message to port */
954 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
955 if (!strncmp(last, "extern:", 7))
956 SPRINT(message->param.notifyinfo.display, "(%d) %s ext", e_select+1, last+7);
958 if (!strncmp(last, "intern:", 7))
959 SPRINT(message->param.notifyinfo.display, "(%d) %s int", e_select+1, last+7);
961 if (!strncmp(last, "chan:", 4))
962 SPRINT(message->param.notifyinfo.display, "(%d) %s chan", e_select+1, last+5);
964 if (!strncmp(last, "vbox:", 5))
965 SPRINT(message->param.notifyinfo.display, "(%d) %s vbox", e_select+1, last+5);
967 SPRINT(message->param.notifyinfo.display, "(%d) %s", e_select+1, (last[0])?last:"- empty -");
968 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s sending display:%s\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
969 message_put(message);
970 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
973 /* process dialing redial
975 void EndpointAppPBX::action_dialing_redial(void)
977 _action_redial_reply(0);
980 /* process dialing reply
982 void EndpointAppPBX::action_dialing_reply(void)
984 _action_redial_reply(1);
988 /* dialing powerdialing delay
990 void EndpointAppPBX::action_dialing_powerdial(void)
992 struct port_list *portlist = ea_endpoint->ep_portlist;
993 struct lcr_msg *message;
994 struct route_param *rparam;
996 /* power dialing only possible if we have a last dialed number */
997 if (!e_ext.last_out[0]) {
998 trace_header("ACTION powerdial (no last number stored)", DIRECTION_NONE);
1000 new_state(EPOINT_STATE_OUT_DISCONNECT);
1001 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1002 set_tone(portlist, "cause_3f");
1007 if ((rparam = routeparam(e_action, PARAM_LIMIT))) {
1008 e_powerlimit = rparam->integer_value;
1014 if ((rparam = routeparam(e_action, PARAM_DELAY))) {
1015 e_powerdelay = rparam->integer_value;
1017 /* delay incomplete */
1018 if (!strchr(e_extdialing, '#'))
1020 *strchr(e_extdialing, '#') = '\0';
1021 e_powerdelay = e_extdialing[0]?atoi(e_extdialing): 0;
1024 if (e_powerdelay < 1)
1026 trace_header("ACTION powerdial (dialing)", DIRECTION_NONE);
1027 add_trace("number", NULL, "%s", e_ext.last_out[0]);
1028 add_trace("delay", NULL, "%d", e_powerdelay);
1031 /* send connect to avoid overlap timeout */
1032 // new_state(EPOINT_STATE_CONNECT); connect may prevent further dialing
1033 if (e_ext.number[0])
1035 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1036 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1037 message_put(message);
1038 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1041 SCPY(e_dialinginfo.id, e_ext.last_out[0]);
1042 e_powerdial_on = 1; /* indicates the existence of powerdialing but no redial time given */
1051 void EndpointAppPBX::action_dialing_callback(void)
1053 struct port_list *portlist = ea_endpoint->ep_portlist;
1054 struct route_param *rparam;
1055 struct extension cbext;
1057 portlist = ea_endpoint->ep_portlist;
1059 /* check given extension */
1060 if (!(rparam = routeparam(e_action, PARAM_EXTENSION))) {
1062 trace_header("ACTION callback (no extension defined)", DIRECTION_NONE);
1066 new_state(EPOINT_STATE_OUT_DISCONNECT);
1067 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1068 set_tone(portlist, "cause_3f");
1070 e_cbcaller[0] = e_cbdialing[0] = '\0';
1074 /* if extension is given */
1075 SCPY(e_cbcaller, rparam->string_value);
1076 if (e_cbcaller[0] == '\0')
1079 /* read callback extension */
1080 memset(&cbext, 0, sizeof(cbext));
1081 if (!read_extension(&cbext, e_cbcaller)) {
1082 trace_header("ACTION callback (extension doesn't exist)", DIRECTION_NONE);
1083 add_trace("extension", NULL, "%s", e_cbcaller);
1088 /* if password is not given */
1089 if (cbext.password[0] == '\0') {
1090 trace_header("ACTION callback (no password set)", DIRECTION_NONE);
1091 add_trace("extension", NULL, "%s", e_cbcaller);
1096 /* callback only possible if callerid exists OR it is given */
1097 if ((rparam = routeparam(e_action, PARAM_CALLTO)))
1098 SCPY(e_cbto, rparam->string_value);
1100 trace_header("ACTION callback (alternative caller id)", DIRECTION_NONE);
1101 add_trace("extension", NULL, "%s", e_cbcaller);
1102 add_trace("callerid", NULL, "%s", e_cbto);
1104 SCPY(e_callerinfo.id, e_cbto);
1105 e_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1106 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1108 if (e_callerinfo.id[0]=='\0' || e_callerinfo.present==INFO_PRESENT_NOTAVAIL) {
1109 trace_header("ACTION callback (no caller ID available)", DIRECTION_NONE);
1110 add_trace("extension", NULL, "%s", e_cbcaller);
1115 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1120 * process hangup 'callback'
1122 void EndpointAppPBX::action_hangup_callback(void)
1124 struct route_param *rparam;
1128 delay = 2; /* default value */
1129 if ((rparam = routeparam(e_action, PARAM_DELAY)))
1130 if (rparam->integer_value>0)
1131 delay = rparam->integer_value;
1133 /* dialing after callback */
1134 if ((rparam = routeparam(e_action, PARAM_PREFIX)))
1135 SCPY(e_cbdialing, rparam->string_value);
1137 SCPY(e_cbdialing, e_extdialing);
1139 trace_header("ACTION callback (dialing)", DIRECTION_NONE);
1140 add_trace("extension", NULL, "%s", e_cbcaller);
1141 add_trace("caller id", NULL, "%s", e_callerinfo.id);
1142 add_trace("delay", NULL, "%d", delay);
1143 add_trace("dialing", NULL, "%s", e_cbdialing);
1146 /* set time to callback */
1147 schedule_timer(&e_callback_timeout, delay, 0);
1152 * dialing action abbreviation
1154 void EndpointAppPBX::action_dialing_abbrev(void)
1156 struct port_list *portlist = ea_endpoint->ep_portlist;
1157 char *abbrev, *phone, *name;
1160 portlist = ea_endpoint->ep_portlist;
1162 /* abbrev dialing is only possible if we have a caller defined */
1163 if (!e_ext.number[0]) {
1164 trace_header("ACTION abbreviation (only for extension)", DIRECTION_NONE);
1166 new_state(EPOINT_STATE_OUT_DISCONNECT);
1167 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1168 set_tone(portlist, "cause_3f");
1172 /* check abbreviation */
1173 abbrev = e_extdialing;
1176 result = parse_phonebook(e_ext.number, &abbrev, &phone, &name);
1178 trace_header("ACTION abbreviation (not found)", DIRECTION_NONE);
1179 add_trace("abbrev", NULL, "%s", abbrev);
1181 new_state(EPOINT_STATE_OUT_DISCONNECT);
1182 message_disconnect_port(portlist, CAUSE_UNALLOCATED, LOCATION_PRIVATE_LOCAL, "");
1183 set_tone(portlist, "cause_01");
1186 if (result == -1) { /* may match if more digits are dialed */
1190 /* dial abbreviation */
1191 trace_header("ACTION abbreviation (dialing)", DIRECTION_NONE);
1192 add_trace("abbrev", NULL, "%s", abbrev);
1193 add_trace("number", NULL, "%s", phone);
1194 if (name) if (name[0])
1195 add_trace("name", NULL, "%s", name);
1197 SCPY(e_dialinginfo.id, phone);
1198 e_extdialing = e_dialinginfo.id;
1204 /* process dialing 'test'
1206 void EndpointAppPBX::action_dialing_test(void)
1210 struct port_list *portlist = ea_endpoint->ep_portlist;
1211 struct lcr_msg *message;
1213 char testcode[32] = "";
1214 struct route_param *rparam;
1216 /* given testcode */
1217 if ((rparam = routeparam(e_action, PARAM_PREFIX)))
1218 SCPY(testcode, rparam->string_value);
1219 SCAT(testcode, e_extdialing);
1221 switch(testcode[0]) {
1223 trace_header("ACTION test", DIRECTION_NONE);
1224 add_trace("test", NULL, "proceeding");
1226 new_state(EPOINT_STATE_IN_PROCEEDING);
1227 set_tone(portlist, "proceeding");
1228 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
1229 message_put(message);
1230 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1234 trace_header("ACTION test", DIRECTION_NONE);
1235 add_trace("test", NULL, "alerting");
1237 new_state(EPOINT_STATE_IN_ALERTING);
1238 set_tone(portlist, "ringpbx");
1239 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
1240 message_put(message);
1241 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1245 trace_header("ACTION test", DIRECTION_NONE);
1246 add_trace("test", NULL, "echo");
1248 new_state(EPOINT_STATE_CONNECT);
1249 if (e_ext.number[0])
1251 set_tone(portlist, NULL);
1252 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1253 SCPY(e_connectinfo.id, e_callerinfo.id);
1254 SCPY(e_connectinfo.extension, e_callerinfo.extension);
1255 e_connectinfo.itype = e_callerinfo.itype;
1256 e_connectinfo.ntype = e_callerinfo.ntype;
1257 e_connectinfo.present = e_callerinfo.present;
1258 e_connectinfo.screen = e_callerinfo.screen;
1259 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1260 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1261 /* handle restricted caller ids */
1262 apply_callerid_restriction(&e_ext, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
1263 /* display callerid if desired for extension */
1264 SCPY(message->param.connectinfo.display, apply_callerid_display(message->param.connectinfo.id, message->param.connectinfo.itype, message->param.connectinfo.ntype, message->param.connectinfo.present, message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name));
1265 message_put(message);
1266 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1268 port = find_port_id(portlist->port_id);
1270 port->set_echotest(1);
1275 trace_header("ACTION test", DIRECTION_NONE);
1276 add_trace("test", NULL, "tone");
1278 new_state(EPOINT_STATE_CONNECT);
1279 if (e_ext.number[0])
1281 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1282 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1283 message_put(message);
1284 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1285 set_tone(portlist, "test");
1289 trace_header("ACTION test", DIRECTION_NONE);
1290 add_trace("test", NULL, "hold music");
1292 new_state(EPOINT_STATE_CONNECT);
1293 if (e_ext.number[0])
1295 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1296 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1297 message_put(message);
1298 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1299 set_tone(portlist, "hold");
1303 if (strlen(testcode) < 4)
1306 cause = atoi(testcode+1);
1309 trace_header("ACTION test", DIRECTION_NONE);
1310 add_trace("test", NULL, "announcement");
1311 add_trace("cause", NULL, "%d", cause);
1313 new_state(EPOINT_STATE_CONNECT);
1314 if (e_ext.number[0])
1316 SPRINT(causestr,"cause_%02x",cause);
1317 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1318 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1319 message_put(message);
1320 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1321 set_tone(portlist, causestr);
1325 if (strlen(testcode) < 4)
1328 cause = atoi(testcode+1);
1331 trace_header("ACTION test", DIRECTION_NONE);
1332 add_trace("test", NULL, "disconnect");
1333 add_trace("cause", NULL, "%d", cause);
1335 new_state(EPOINT_STATE_OUT_DISCONNECT);
1336 SPRINT(causestr,"cause_%02x",cause);
1337 message_disconnect_port(portlist, cause, LOCATION_PRIVATE_LOCAL, "");
1338 set_tone(portlist, causestr);
1341 case '8': /* release */
1342 trace_header("ACTION test", DIRECTION_NONE);
1343 add_trace("test", NULL, "release");
1344 add_trace("cause", NULL, "16");
1346 new_state(EPOINT_STATE_OUT_DISCONNECT);
1347 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1348 set_tone(portlist, "release");
1351 case '9': /* text callerid test */
1352 trace_header("ACTION test", DIRECTION_NONE);
1353 add_trace("test", NULL, "callerid");
1355 new_state(EPOINT_STATE_CONNECT);
1356 if (e_ext.number[0])
1358 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
1359 SCPY(e_connectinfo.id, "12345678");
1360 SCPY(e_connectinfo.name, "Welcome to LCR");
1361 SCPY(e_connectinfo.display, "Welcome to LCR");
1362 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1363 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1364 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
1365 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(message->param.connectinfo));
1366 message_put(message);
1367 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1368 set_tone(portlist, "hold");
1374 /* process init play
1376 void EndpointAppPBX::action_init_play(void)
1378 struct route_param *rparam;
1379 struct port_list *portlist = ea_endpoint->ep_portlist;
1381 /* check given sample */
1382 if (!(rparam = routeparam(e_action, PARAM_SAMPLE))) {
1383 trace_header("ACTION play (no sample given)", DIRECTION_NONE);
1387 new_state(EPOINT_STATE_OUT_DISCONNECT);
1388 message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
1389 set_tone(portlist, "cause_3f");
1394 /* if sample is given */
1395 if (rparam->string_value[0] == '\0') {
1396 trace_header("ACTION play (no sample given)", DIRECTION_NONE);
1401 if (e_ext.number[0])
1404 set_tone(ea_endpoint->ep_portlist, rparam->string_value);
1409 * action_*_vbox_play is implemented in "action_vbox.cpp"
1414 * process dialing of calculator
1416 void EndpointAppPBX::action_dialing_calculator(void)
1418 struct port_list *portlist = ea_endpoint->ep_portlist;
1419 struct lcr_msg *message;
1420 double value1, value2, v, sign1;
1421 int komma1, komma2, k, state, mode = 0, first;
1424 portlist = ea_endpoint->ep_portlist;
1426 /* remove error message */
1427 if (!strncmp(e_extdialing, "Error", 5)) {
1428 UCPY(e_extdialing, e_extdialing+5);
1430 if (!strncmp(e_extdialing, "inf", 3)) {
1431 UCPY(e_extdialing, e_extdialing+3);
1433 if (!strncmp(e_extdialing, "-inf", 4)) {
1434 UCPY(e_extdialing, e_extdialing+4);
1437 /* process dialing */
1449 if (*p>='0' && *p<='9') {
1455 if ((p[-1]<'0' || p[-1]>'0') && p[-1]!='.') {
1462 case 0: /* first number */
1464 value1 = value1*10 + (*p-'0');
1473 case 1: /* second number */
1475 value2 = value2*10 + (*p-'0');
1489 UCPY(e_extdialing, "Error");
1492 /* if there is a multiplication, we change to / */
1500 /* if there is a division, we change to + */
1508 /* if there is a addition, we change to - */
1516 /* if there is a substraction and a comma, we change to * */
1517 if (p[-1]=='-' && komma1) {
1524 /* if there is a substraction and no comma and the first or second value, we change to , */
1532 /* if there is a komma and we are at the first value, we change to * */
1533 if (p[-1]=='.' && state==0) {
1541 /* if there is a komma and we are at the second value, we display error */
1542 if (komma2 && state==1) {
1543 UCPY(e_extdialing, "Error");
1546 /* if we are at state 1, we write a comma */
1552 /* we assume multiplication */
1559 /* if just a number is displayed, the input is cleared */
1561 *e_extdialing = '\0';
1564 /* calculate the result */
1566 case 0: /* multiply */
1567 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1*value2);
1569 case 1: /* divide */
1570 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1/value2);
1573 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1+value2);
1575 case 3: /* substract */
1576 UNPRINT(e_extdialing, sizeof(e_dialinginfo.id)-strlen(e_dialinginfo.id), "%.8f", sign1*value1-value2);
1579 e_dialinginfo.id[sizeof(e_dialinginfo.id)-1] = '\0';
1580 if (strchr(e_extdialing, '.')) { /* remove zeroes */
1581 while (e_extdialing[strlen(e_extdialing)-1] == '0')
1582 e_extdialing[strlen(e_extdialing)-1] = '\0';
1583 if (e_extdialing[strlen(e_extdialing)-1] == '.')
1584 e_extdialing[strlen(e_extdialing)-1] = '\0'; /* and remove dot */
1586 p = strchr(e_extdialing,'\0')-1;
1618 UCPY(e_extdialing, "Error");
1627 /* display dialing */
1628 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1629 SPRINT(message->param.notifyinfo.display, ">%s", e_extdialing);
1630 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s displaying interpreted dialing '%s' internal values: %f %f\n", ea_endpoint->ep_serial, e_ext.number, e_extdialing, value1, value2);
1631 message_put(message);
1632 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1637 * process dialing of timer
1639 void EndpointAppPBX::action_dialing_timer(void)
1645 * process 'goto' or 'menu'
1647 void EndpointAppPBX::_action_goto_menu(int mode)
1649 struct port_list *portlist = ea_endpoint->ep_portlist;
1650 struct route_param *rparam;
1652 /* check given ruleset */
1653 if (!(rparam = routeparam(e_action, PARAM_RULESET))) {
1655 trace_header("ACTION goto/menu (no ruleset given)", DIRECTION_NONE);
1659 new_state(EPOINT_STATE_OUT_DISCONNECT);
1660 message_disconnect_port(portlist, CAUSE_SERVICEUNAVAIL, LOCATION_PRIVATE_LOCAL, "");
1661 set_tone(portlist, "cause_3f");
1665 if (rparam->string_value[0] == '\0')
1667 e_ruleset = getrulesetbyname(rparam->string_value);
1669 trace_header("ACTION goto/menu (ruleset not found)", DIRECTION_NONE);
1670 add_trace("ruleset", NULL, "%s", rparam->string_value);
1675 /* if the 'menu' was selected, we will flush all digits */
1677 e_dialinginfo.id[0] = 0;
1678 e_extdialing = e_dialinginfo.id;
1680 /* remove digits that are required to match the rule */
1681 if ((rparam = routeparam(e_action, PARAM_STRIP))) {
1683 SCPY(e_dialinginfo.id, e_extdialing);
1684 e_extdialing = e_dialinginfo.id;
1689 trace_header("ACTION goto/menu (change to)", DIRECTION_NONE);
1690 add_trace("ruleset", NULL, "%s", e_ruleset->name);
1691 if (e_dialinginfo.id[0]) {
1692 add_trace("dialing", NULL, "%s", e_dialinginfo.id);
1694 if ((rparam = routeparam(e_action, PARAM_SAMPLE))) {
1695 add_trace("sample", NULL, "%s", rparam->string_value);
1697 set_tone(ea_endpoint->ep_portlist, rparam->string_value);
1702 /* do dialing with new ruleset */
1707 /* process dialing goto
1709 void EndpointAppPBX::action_dialing_goto(void)
1711 _action_goto_menu(0);
1714 /* process dialing menu
1716 void EndpointAppPBX::action_dialing_menu(void)
1718 _action_goto_menu(1);
1723 * process dialing disconnect
1725 void EndpointAppPBX::action_dialing_disconnect(void)
1727 struct route_param *rparam;
1728 struct port_list *portlist = ea_endpoint->ep_portlist;
1729 struct lcr_msg *message;
1730 int cause = CAUSE_NORMAL; /* normal call clearing */
1731 int location = LOCATION_PRIVATE_LOCAL;
1732 char cause_string[256] = "", display[84] = "";
1734 /* check cause parameter */
1735 if ((rparam = routeparam(e_action, PARAM_CAUSE))) {
1736 cause = rparam->integer_value;
1737 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'cause' is given: %d\n", ea_endpoint->ep_serial, cause);
1739 if ((rparam = routeparam(e_action, PARAM_LOCATION))) {
1740 location = rparam->integer_value;
1741 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'location' is given: %d\n", ea_endpoint->ep_serial, location);
1745 /* use cause as sample, if not given later */
1746 SPRINT(cause_string, "cause_%02x", cause);
1748 /* check sample parameter */
1749 if ((rparam = routeparam(e_action, PARAM_SAMPLE))) {
1750 SCPY(cause_string, rparam->string_value);
1751 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'sample' is given: %s\n", ea_endpoint->ep_serial, cause_string);
1755 if ((rparam = routeparam(e_action, PARAM_DISPLAY))) {
1756 SCPY(display, rparam->string_value);
1757 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'display' is given: %s\n", ea_endpoint->ep_serial, display);
1760 /* disconnect only if connect parameter is not given */
1761 trace_header("ACTION disconnect", DIRECTION_NONE);
1762 add_trace("cause", "value", "%d", cause);
1763 add_trace("cause", "location", "%d", location);
1764 if (cause_string[0])
1765 add_trace("sample", NULL, "%s", cause_string);
1767 add_trace("display", NULL, "%s", display);
1769 new_state(EPOINT_STATE_OUT_DISCONNECT);
1770 set_tone(portlist, cause_string);
1771 if (!(rparam = routeparam(e_action, PARAM_CONNECT))) {
1772 message_disconnect_port(portlist, cause, location, display);
1774 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1775 SCPY(message->param.notifyinfo.display, display);
1776 message_put(message);
1777 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1784 * process dialing release
1786 void EndpointAppPBX::action_dialing_release(void)
1788 struct route_param *rparam;
1789 int cause = CAUSE_NORMAL; /* normal call clearing */
1790 int location = LOCATION_PRIVATE_LOCAL;
1791 char cause_string[256] = "", display[84] = "";
1793 /* check cause parameter */
1794 if ((rparam = routeparam(e_action, PARAM_CAUSE))) {
1795 cause = rparam->integer_value;
1796 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'cause' is given: %d\n", ea_endpoint->ep_serial, cause);
1798 if ((rparam = routeparam(e_action, PARAM_LOCATION))) {
1799 location = rparam->integer_value;
1800 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'location' is given: %d\n", ea_endpoint->ep_serial, location);
1804 /* use cause as sample, if not given later */
1805 SPRINT(cause_string, "cause_%02x", cause);
1808 if ((rparam = routeparam(e_action, PARAM_DISPLAY))) {
1809 SCPY(display, rparam->string_value);
1810 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): 'display' is given: %s\n", ea_endpoint->ep_serial, display);
1813 /* disconnect only if connect parameter is not given */
1814 trace_header("ACTION release", DIRECTION_NONE);
1815 add_trace("cause", "value", "%d", cause);
1816 add_trace("cause", "location", "%d", location);
1818 add_trace("display", NULL, "%s", display);
1821 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, location, cause, 1);
1826 * process dialing help
1828 void EndpointAppPBX::action_dialing_help(void)
1830 /* show all things that would match */
1832 struct numbering *numbering = numbering_int;
1833 char dialing[sizeof(e_dialinginfo.id)];
1835 struct lcr_msg *message;
1836 struct route_param *rparam;
1838 /* in case we have no menu (this should never happen) */
1843 if (strchr(e_dialinginfo.id,'*')) {
1845 e_dialinginfo.id[0] = '\0';
1847 if (strchr(e_dialinginfo.id,'#')) {
1849 e_dialinginfo.id[0] = '\0';
1852 /* get position in menu */
1854 /* get last menu position */
1856 while(numbering->next) {
1858 numbering = numbering->next;
1861 /* get menu position */
1864 numbering = numbering->next;
1867 numbering = numbering_int;
1874 /* if we dial something else we need to add the prefix and change the action */
1875 if (e_dialinginfo.id[0]) {
1876 e_action = NUMB_ACTION_NONE;
1877 SCPY(dialing, numbering->prefix);
1878 //we ignore the first digit after selecting
1879 //SCAT(dialing, e_dialinginfo.id);
1880 SCPY(e_dialinginfo.id, dialing);
1881 e_extdialing = e_dialinginfo.id+strlen(numbering->prefix);
1882 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' dialing: %s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], e_dialinginfo.id);
1888 /* send display message to port */
1889 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
1890 SPRINT(message->param.notifyinfo.display, ">%s %s%s%s", numbering->prefix, numb_actions[numbering->action], (numbering->param[0])?" ":"", numbering->param);
1891 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s selected a new menu '%s' sending display:%s\n", ea_endpoint->ep_serial, e_ext.number, numb_actions[numbering->action], message->param.notifyinfo.display);
1892 message_put(message);
1893 logmessage(message->type, message->paramea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1899 * process dialing deflect
1901 void EndpointAppPBX::action_dialing_deflect(void)
1907 * process dialing setforward
1909 void EndpointAppPBX::action_dialing_setforward(void)
1914 * process init 'execute'
1916 void EndpointAppPBX::action_init_execute(void)
1918 struct route_param *rparam;
1919 int executeon = INFO_ON_HANGUP; /* Use Hangup as a default for compatibility */
1921 /* Get the execute on parameter */
1922 if ((rparam = routeparam(e_action, PARAM_ON)))
1923 executeon = rparam->integer_value;
1925 /* Execute this action if init was specified */
1926 if (executeon == INFO_ON_INIT) {
1927 trace_header("ACTION execute ON init", DIRECTION_NONE);
1934 * process hangup 'execute'
1936 void EndpointAppPBX::action_hangup_execute(void)
1938 struct route_param *rparam;
1939 int executeon = INFO_ON_HANGUP; /* Use Hangup as a default for compatibility */
1941 /* Get the execute on parameter */
1942 if ((rparam = routeparam(e_action, PARAM_ON)))
1943 executeon = rparam->integer_value;
1945 /* Execute this action if init was specified */
1946 if (executeon == INFO_ON_HANGUP) {
1947 trace_header("ACTION execute ON hangup", DIRECTION_NONE);
1954 * process 'execute' from action_init_execute or action_hangup_execute
1956 void EndpointAppPBX::action_execute(void)
1958 struct route_param *rparam;
1962 char *command = (char *)"";
1964 char *argv[11]; /* check also number of args below */
1967 /* get script / command */
1968 if ((rparam = routeparam(e_action, PARAM_EXECUTE)))
1969 command = rparam->string_value;
1970 if (command[0] == '\0') {
1971 trace_header("ACTION execute (no parameter given)", DIRECTION_NONE);
1975 argv[i++] = (char *)"/bin/sh";
1976 argv[i++] = (char *)"-c";
1977 argv[i++] = command;
1978 argv[i++] = command;
1979 if ((rparam = routeparam(e_action, PARAM_PARAM))) {
1980 argv[i++] = rparam->string_value;
1982 argv[i++] = e_extdialing;
1983 argv[i++] = (char *)numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international);
1984 argv[i++] = e_callerinfo.extension;
1985 argv[i++] = e_callerinfo.name;
1986 SPRINT(isdn_port, "%d", e_callerinfo.isdn_port);
1987 argv[i++] = isdn_port;
1988 argv[i++] = NULL; /* check also number of args above */
1989 switch (pid = fork ()) {
1991 trace_header("ACTION execute (fork failed)", DIRECTION_NONE);
1995 /* To be shure there are no zombies created double fork */
1996 if ((pid2 = fork()) == 0) {
1997 execve("/bin/sh", argv, environ);
2000 /* Exit immediately and release the waiting parent. The subprocess falls to init because the parent died */
2005 trace_header("ACTION execute", DIRECTION_NONE);
2006 add_trace("command", NULL, "%s", command);
2009 /* Wait for the pid. The forked process will exit immediately so there is no problem waiting. */
2010 waitpid(pid, &iWaitStatus, 0);
2017 * process hangup 'file'
2019 void EndpointAppPBX::action_hangup_file(void)
2021 struct route_param *rparam;
2022 const char *file, *content, *mode;
2025 /* get file / content */
2026 if (!(rparam = routeparam(e_action, PARAM_FILE)))
2027 file = rparam->string_value;
2030 if (!(rparam = routeparam(e_action, PARAM_CONTENT)))
2031 content = rparam->string_value;
2033 content = e_extdialing;
2034 if (!(rparam = routeparam(e_action, PARAM_APPEND)))
2038 if (file[0] == '\0') {
2039 trace_header("ACTION file (no filename given)", DIRECTION_NONE);
2043 if (!(fp = fopen(file, mode))) {
2044 trace_header("ACTION file (failed to open)", DIRECTION_NONE);
2045 add_trace("file", "name", "%s", file);
2046 add_trace("file", "mode", "%s", (mode[0]=='w')?"write":"append");
2050 trace_header("ACTION file", DIRECTION_NONE);
2051 add_trace("file", "name", "%s", file);
2052 add_trace("file", "mode", "%s", (mode[0]=='w')?"write":"append");
2053 add_trace("content", NULL, "%s", content);
2055 fprintf(fp, "%s\n", content);
2061 * process init 'pick'
2063 void EndpointAppPBX::action_init_pick(void)
2065 struct route_param *rparam;
2066 char *extensions = NULL;
2068 if ((rparam = routeparam(e_action, PARAM_EXTENSIONS)))
2069 extensions = rparam->string_value;
2071 trace_header("ACTION pick", DIRECTION_NONE);
2072 if (extensions) if (extensions[0])
2073 add_trace("extensions", NULL, "%s", extensions);
2075 pick_join(extensions);
2080 * process dialing 'password'
2082 void EndpointAppPBX::action_dialing_password(void)
2084 struct port_list *portlist = ea_endpoint->ep_portlist;
2086 /* prompt for password */
2087 if (e_extdialing[0] == '\0') {
2088 /* give password tone */
2089 set_tone(portlist, "password");
2091 if (e_extdialing[1] == '\0') {
2092 /* give password tone */
2093 set_tone(portlist, "dialing");
2096 /* wait until all digits are dialed */
2097 if (strlen(e_ext.password) != strlen(e_extdialing))
2098 return; /* more digits needed */
2100 /* check the password */
2101 if (e_ext.password[0]=='\0' || (strlen(e_ext.password)==strlen(e_extdialing) && !!strcmp(e_ext.password,e_extdialing))) {
2102 trace_header("ACTION password_write (wrong password)", DIRECTION_NONE);
2103 add_trace("dialed", NULL, "%s", e_extdialing);
2105 e_connectedmode = 0;
2107 new_state(EPOINT_STATE_OUT_DISCONNECT);
2108 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
2109 set_tone(portlist, "cause_10");
2113 /* write caller id if ACTION_PASSWORD_WRITE was selected */
2115 if (e_action->index == ACTION_PASSWORD_WRITE) {
2116 append_callbackauth(e_ext.number, &e_callbackinfo);
2117 trace_header("ACTION password_write (written)", DIRECTION_NONE);
2118 add_trace("dialed", NULL, "%s", e_extdialing);
2122 /* make call state */
2123 new_state(EPOINT_STATE_IN_OVERLAP);
2124 e_ruleset = ruleset_main;
2126 e_rule = e_ruleset->rule_first;
2128 e_dialinginfo.id[0] = '\0';
2129 e_extdialing = e_dialinginfo.id;
2130 set_tone(portlist, "dialpbx");
2133 void EndpointAppPBX::action_dialing_password_wr(void)
2135 action_dialing_password();
2139 /* general process dialing of incoming call
2140 * depending on the detected prefix, subfunctions above (action_*) will be
2143 void EndpointAppPBX::process_dialing(int timeout)
2145 struct port_list *portlist = ea_endpoint->ep_portlist;
2146 struct lcr_msg *message;
2147 struct route_param *rparam;
2148 struct timeval current_time;
2150 /* set if timeout is active, or if timeout value was given due to timeout action */
2151 if (e_action_timeout.active)
2154 //#warning Due to HANG-BUG somewhere here, I added some HANG-BUG-DEBUGGING output that cannot be disabled. after bug has been found, this will be removed.
2155 //PDEBUG(~0, "HANG-BUG-DEBUGGING: entered porcess_dialing\n");
2156 portlist = ea_endpoint->ep_portlist;
2157 /* check if we have a port instance linked to our epoint */
2160 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): note: dialing call requires exactly one port object to process dialing. this case could happen due to a parked call. we end dialing here.\n", ea_endpoint->ep_serial, e_ext.number);
2161 unsched_timer(&e_action_timeout);
2162 unsched_timer(&e_match_timeout);
2165 if (portlist->next) {
2166 goto portlist_error;
2169 /* check nesting levels */
2170 if (++e_rule_nesting > RULE_NESTING) {
2171 trace_header("ACTION (nesting too deep)", DIRECTION_NONE);
2172 add_trace("max-levels", NULL, "%d", RULE_NESTING);
2174 new_state(EPOINT_STATE_OUT_DISCONNECT);
2175 message_disconnect_port(portlist, CAUSE_UNSPECIFIED, LOCATION_PRIVATE_LOCAL, "");
2176 set_tone(portlist, "cause_3f");
2177 unsched_timer(&e_action_timeout);
2178 unsched_timer(&e_match_timeout);
2182 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before action-timeout processing\n");
2183 /* process timeout */
2184 if (e_action && timeout) { /* e_action may be NULL, but e_action_timeout may still be set and must be ignored */
2185 unsched_timer(&e_action_timeout);
2186 if (e_state == EPOINT_STATE_CONNECT) {
2187 PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, but we already have connected, so we stop timer and continue.\n", ea_endpoint->ep_serial);
2190 if (e_action->index == ACTION_DISCONNECT
2191 || e_state == EPOINT_STATE_OUT_DISCONNECT) {
2192 /* release after disconnect */
2193 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2196 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0, 0, 0);
2197 e_action = e_action->next;
2199 /* nothing more, so we release */
2200 PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action timed out, and we have no next action, so we disconnect.\n", ea_endpoint->ep_serial);
2201 new_state(EPOINT_STATE_OUT_DISCONNECT);
2202 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
2203 set_tone(portlist, "cause_3f");
2206 goto action_timeout;
2209 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before setup/overlap state checking\n");
2210 if (e_state!=EPOINT_STATE_IN_SETUP
2211 && e_state!=EPOINT_STATE_IN_OVERLAP) {
2212 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): we are not in incoming setup/overlap state, so we ignore init/dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
2213 unsched_timer(&e_match_timeout);
2218 /* check if we do menu selection */
2219 if (e_action==NUMB_ACTION_NONE && (e_dialinginfo.id[0]=='*' || e_dialinginfo.id[0]=='#'))
2220 /* do menu selection */
2221 if (e_ext.display_menu) {
2222 if (portlist->port_type==PORT_TYPE_DSS1_NT_IN || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) { /* only if the dialing terminal is an isdn telephone connected to an internal port */
2223 e_dialinginfo.id[0] = '\0';
2224 e_action = NUMB_ACTION_MENU;
2227 unsched_timer(&e_match_timeout);
2230 /* invalid dialing */
2231 message_disconnect_port(portlist, CAUSE_INCALID, LOCATION_PRIVATE_LOCAL, "");
2232 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
2233 message->param.disconnectinfo.cause = CAUSE_INVALID;
2234 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2236 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2237 SCPY(message->param.notifyinfo.display,get_isdn_cause(LOCATION_PRIVATE_LOCAL, epoint->e_ext.display_cause, param->disconnectinfo.location, param->disconnectinfo.cause));
2239 message_put(message);
2240 logmessage(message->type, message->param, portlist->port_id, DIRECTION_OUT);
2242 new_state(EPOINT_STATE_OUT_DISCONNECT);
2243 set_tone(portlist,"cause_1c");
2244 unsched_timer(&e_match_timeout);
2249 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before e_action==NULL\n");
2250 /* if no action yet, we will call try to find a matching rule */
2252 /* be sure that all selectors are initialized */
2255 /* check for external call */
2256 if (!strncmp(e_dialinginfo.id, "extern:", 7)) {
2257 e_extdialing = e_dialinginfo.id+7;
2258 e_action = &action_external;
2259 goto process_action;
2261 /* check for internal call */
2262 if (!strncmp(e_dialinginfo.id, "intern:", 7)) {
2263 e_extdialing = e_dialinginfo.id+7;
2264 e_action = &action_internal;
2265 goto process_action;
2267 /* check for chan call */
2268 if (!strncmp(e_dialinginfo.id, "remote:", 7)) {
2269 e_extdialing = e_dialinginfo.id+7;
2270 e_action = &action_remote;
2271 goto process_action;
2273 /* check for vbox call */
2274 if (!strncmp(e_dialinginfo.id, "vbox:", 5)) {
2275 e_extdialing = e_dialinginfo.id+5;
2276 e_action = &action_vbox;
2277 goto process_action;
2280 gettimeofday(¤t_time, NULL);
2281 if (timeout && TIME_SMALLER(&e_match_timeout.timeout, ¤t_time)) {
2282 /* return timeout rule */
2283 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', timeout in ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name);
2284 unsched_timer(&e_match_timeout);
2285 e_action = e_match_to_action;
2286 e_extdialing = e_match_to_extdialing;
2287 trace_header("ROUTING (timeout)", DIRECTION_NONE);
2288 add_trace("action", NULL, "%s", action_defs[e_action->index].name);
2289 add_trace("line", NULL, "%d", e_action->line);
2292 //PDEBUG(~0, "HANG-BUG-DEBUGGING: before routing\n");
2293 /* check for matching rule */
2294 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' dialing: '%s', checking matching rule of ruleset '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id, e_ruleset->name);
2296 e_action = route(e_ruleset);
2298 trace_header("ACTION (match)", DIRECTION_NONE);
2299 add_trace("action", NULL, "%s", action_defs[e_action->index].name);
2300 add_trace("line", NULL, "%d", e_action->line);
2304 e_action = &action_disconnect;
2306 trace_header("ACTION (no main ruleset, disconnecting)", DIRECTION_NONE);
2310 //PDEBUG(~0, "HANG-BUG-DEBUGGING: after routing\n");
2313 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): no rule within the current ruleset matches yet.\n", ea_endpoint->ep_serial, e_ext.number);
2318 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): a rule with action '%s' matches.\n", ea_endpoint->ep_serial, action_defs[e_action->index].name);
2323 unsched_timer(&e_action_timeout);
2324 if (e_action->timeout) {
2325 schedule_timer(&e_action_timeout, e_action->timeout, 0);
2326 PDEBUG(DEBUG_ROUTE|DEBUG_EPOINT, "EPOINT(%d): action has a timeout of %d secods.\n", ea_endpoint->ep_serial, e_action->timeout);
2330 /* check param proceeding / alerting / connect */
2331 if ((rparam = routeparam(e_action, PARAM_CONNECT))) {
2332 /* NOTE: we may not change our state to connect, because dialing will then not possible */
2334 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2335 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2336 message_put(message);
2337 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2339 if ((rparam = routeparam(e_action, PARAM_ALERTING))) {
2340 /* NOTE: we may not change our state to alerting, because dialing will then not possible */
2341 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2342 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2343 message_put(message);
2344 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2346 if ((rparam = routeparam(e_action, PARAM_PROCEEDING))) {
2347 /* NOTE: we may not change our state to proceeding, because dialing will then not possible */
2348 memset(&e_connectinfo, 0, sizeof(e_connectinfo));
2349 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2350 message_put(message);
2351 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2354 if (action_defs[e_action->index].init_func) {
2355 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: current action '%s' has a init function, so we call it...\n", ea_endpoint->ep_serial, e_ext.number, action_defs[e_action->index].name);
2356 (this->*(action_defs[e_action->index].init_func))();
2358 if (e_state!=EPOINT_STATE_IN_SETUP
2359 && e_state!=EPOINT_STATE_IN_OVERLAP) {
2360 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): AFTER init process: we are not in incoming setup/overlap state anymore, so we ignore further dialing process.\n", ea_endpoint->ep_serial, e_rule_nesting);
2361 goto display_action;
2365 /* show what we are doing */
2366 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s' action: %s (dialing '%s')\n", ea_endpoint->ep_serial, e_ext.number, action_defs[e_action->index].name, e_extdialing);
2367 /* go to action's dialing function */
2368 if (action_defs[e_action->index].dialing_func) {
2369 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: current action '%s' has a dialing function, so we call it...\n", ea_endpoint->ep_serial, e_ext.number, action_defs[e_action->index].name);
2370 (this->*(action_defs[e_action->index].dialing_func))();
2373 /* display selected dialing action if enabled and still in setup state */
2376 if (e_action->index==ACTION_MENU
2377 || e_action->index==ACTION_REDIAL
2378 || e_action->index==ACTION_REPLY
2379 || e_action->index==ACTION_TIMER
2380 || e_action->index==ACTION_CALCULATOR
2381 || e_action->index==ACTION_TEST)
2385 if (!e_ext.display_dialing)
2387 if (e_state==EPOINT_STATE_IN_OVERLAP || e_state==EPOINT_STATE_IN_PROCEEDING || e_state==EPOINT_STATE_IN_ALERTING || e_state==EPOINT_STATE_CONNECT/* || e_state==EPOINT_STATE_IN_DISCONNECT || e_state==EPOINT_STATE_OUT_DISCONNECT*/)
2388 if (portlist->port_type==PORT_TYPE_DSS1_NT_IN || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) { /* only if the dialing terminal is an isdn telephone connected to an internal port */
2389 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2392 SPRINT(message->param.notifyinfo.display, "> %s", e_dialinginfo.id);
2394 SPRINT(message->param.notifyinfo.display, "%s%s%s", action_defs[e_action->index].name, (e_extdialing[0])?" ":"", e_extdialing);
2397 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s displaying interpreted dialing '%s'\n", ea_endpoint->ep_serial, e_ext.number, message->param.notifyinfo.display);
2398 message_put(message);
2399 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2408 /* some services store information after hangup */
2409 void EndpointAppPBX::process_hangup(int cause, int location)
2411 char callertext[256], dialingtext[256];
2412 int writeext = 0, i;
2414 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2415 if (e_ext.number[0]) {
2416 if (read_extension(&e_ext, e_ext.number))
2425 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): writing connect from %s to %s into logfile of %s\n", ea_endpoint->ep_serial, e_callerinfo.id, e_dialinginfo.id, e_ext.number);
2426 switch(e_dialinginfo.itype) {
2427 case INFO_ITYPE_CHAN:
2428 SPRINT(dialingtext, "chan:%s", e_dialinginfo.id);
2430 case INFO_ITYPE_ISDN_EXTENSION:
2431 SPRINT(dialingtext, "intern:%s", e_dialinginfo.id);
2433 case INFO_ITYPE_VBOX:
2434 SPRINT(dialingtext, "vbox:%s", e_dialinginfo.id);
2437 SPRINT(dialingtext, "%s", e_dialinginfo.id);
2440 if (e_callerinfo.id[0])
2441 SPRINT(callertext, "%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
2443 SPRINT(callertext, "unknown");
2444 /* allpy restriction */
2445 if (!e_ext.anon_ignore && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
2446 SPRINT(callertext, "anonymous");
2447 if (e_callerinfo.extension[0]) /* add intern if present */
2448 UNPRINT(strchr(callertext,'\0'), sizeof(callertext)-1+strlen(callertext), " (intern %s)", e_callerinfo.extension);
2449 write_log(e_ext.number, callertext, dialingtext, e_start, e_stop, 0, cause, location);
2451 /* store last received call for reply-list */
2452 if (e_origin == 1) // outgoing to phone is incoming for user
2453 if (e_callerinfo.id[0] || e_callerinfo.extension[0])
2454 if (e_ext.anon_ignore || e_callerinfo.present!=INFO_PRESENT_RESTRICTED) {
2455 if (e_callerinfo.extension[0])
2456 SPRINT(callertext, "intern:%s", e_callerinfo.extension);
2458 SPRINT(callertext, "extern:%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
2459 if (!!strcmp(callertext, e_ext.last_in[0])) {
2462 UCPY(e_ext.last_in[i], e_ext.last_in[i-1]);
2465 SCPY(e_ext.last_in[0], callertext);
2466 writeext |= 1; /* store extension later */
2467 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing last received caller id '%s'.\n", ea_endpoint->ep_serial, e_ext.number, e_ext.last_in[0]);
2469 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last received id '%s' because it is identical with the last one.\n", ea_endpoint->ep_serial, e_ext.number, callertext);
2472 /* store last made call for reply-list */
2473 if (e_origin == 0) // incoming from phone is outgoing for user
2474 if (e_dialinginfo.id[0]) {
2475 if (!!strcmp(e_dialinginfo.id, e_ext.last_out[0])) {
2478 UCPY(e_ext.last_out[i], e_ext.last_out[i-1]);
2481 SCPY(e_ext.last_out[0], e_dialinginfo.id);
2482 writeext |= 1; /* store extension later */
2483 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: storing last number '%s'.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
2485 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: cannot store last number '%s' because it is identical with the last one.\n", ea_endpoint->ep_serial, e_ext.number, e_dialinginfo.id);
2488 /* write extension if needed */
2489 if (writeext == 0x11)
2490 write_extension(&e_ext, e_ext.number);
2493 if (action_defs[e_action->index].hangup_func) {
2494 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): terminal %s: current action '%s' has a hangup function, so we call it...\n", ea_endpoint->ep_serial, e_ext.number, action_defs[e_action->index].name);
2495 (this->*(action_defs[e_action->index].hangup_func))();