1 /*****************************************************************************\
3 ** Linux Call Router **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** The EndpointAppPBX implements PBX4Linux **
10 \*****************************************************************************/
15 class EndpointAppPBX *apppbx_first = NULL;
17 int action_timeout(struct lcr_timer *timer, void *instance, int index);
18 int match_timeout(struct lcr_timer *timer, void *instance, int index);
19 int redial_timeout(struct lcr_timer *timer, void *instance, int index);
20 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index);
21 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index);
22 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index);
23 int password_timeout(struct lcr_timer *timer, void *instance, int index);
24 int callback_timeout(struct lcr_timer *timer, void *instance, int index);
27 * EndpointAppPBX constructor
29 EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin, EAPP_TYPE_PBX)
31 class EndpointAppPBX **apppointer;
34 memset(&e_crypt_handler, 0, sizeof(e_crypt_handler));
35 add_timer(&e_crypt_handler, crypt_handler, this, 0);
37 memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh));
38 add_timer(&e_vbox_refresh, vbox_refresh, this, 0);
39 memset(&e_action_timeout, 0, sizeof(e_action_timeout));
40 add_timer(&e_action_timeout, action_timeout, this, 0);
41 memset(&e_match_timeout, 0, sizeof(e_match_timeout));
42 add_timer(&e_match_timeout, match_timeout, this, 0);
43 memset(&e_redial_timeout, 0, sizeof(e_redial_timeout));
44 add_timer(&e_redial_timeout, redial_timeout, this, 0);
45 memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout));
46 add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0);
47 memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout));
48 add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0);
49 memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout));
50 add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0);
51 memset(&e_callback_timeout, 0, sizeof(e_callback_timeout));
52 add_timer(&e_callback_timeout, callback_timeout, this, 0);
53 memset(&e_password_timeout, 0, sizeof(e_password_timeout));
54 add_timer(&e_password_timeout, password_timeout, this, 0);
57 /* add application to chain */
59 apppointer = &apppbx_first;
61 apppointer = &((*apppointer)->next);
65 memset(&e_ext, 0, sizeof(struct extension));
66 // *************** NOTE: also change value in read_extension() **************
67 e_ext.rights = 4; /* international */
68 e_ext.rx_gain = e_ext.tx_gain = 0;
69 e_state = EPOINT_STATE_IDLE;
70 e_ext.number[0] = '\0';
71 e_extension_interface[0] = '\0';
72 memset(&e_callerinfo, 0, sizeof(struct caller_info));
73 memset(&e_dialinginfo, 0, sizeof(struct dialing_info));
74 memset(&e_connectinfo, 0, sizeof(struct connect_info));
75 memset(&e_redirinfo, 0, sizeof(struct redir_info));
76 memset(&e_capainfo, 0, sizeof(struct capa_info));
77 memset(&e_rtpinfo, 0, sizeof(struct rtp_info));
80 e_ruleset = ruleset_main;
82 e_rule = e_ruleset->rule_first;
85 e_match_to_action = NULL;
87 e_extdialing = e_dialinginfo.id;
91 // e_join_tone[0] = e_hold_tone[0] = '\0';
92 e_join_pattern /*= e_hold_pattern*/ = 0;
94 e_adminid = 0; // will be set, if call was initiated via admin socket
97 e_cbdialing[0] = '\0';
100 memset(&e_callbackinfo, 0, sizeof(struct caller_info));
106 e_multipoint_cause = 0;
107 e_multipoint_location = 0;
108 e_dialing_queue[0] = '\0';
111 e_crypt_state = CM_ST_NULL;
112 e_crypt_keyengine_busy = 0;
113 e_crypt_info[0] = '\0';
117 e_tx_state = NOTIFY_STATE_ACTIVE;
118 e_rx_state = NOTIFY_STATE_ACTIVE;
119 e_join_cause = e_join_location = 0;
120 /*********************************
121 *********************************
122 ********* ATTENTION *************
123 *********************************
124 *********************************/
125 /* if you add new values, that must be initialized, also check if they must
126 * be initialized when doing callback
132 * EpointAppPBX destructor
134 EndpointAppPBX::~EndpointAppPBX(void)
136 class EndpointAppPBX *temp, **tempp;
139 del_timer(&e_crypt_handler);
141 del_timer(&e_vbox_refresh);
142 del_timer(&e_action_timeout);
143 del_timer(&e_match_timeout);
144 del_timer(&e_redial_timeout);
145 del_timer(&e_powerdial_timeout);
146 del_timer(&e_cfnr_timeout);
147 del_timer(&e_cfnr_call_timeout);
148 del_timer(&e_callback_timeout);
149 del_timer(&e_password_timeout);
153 tempp = &apppbx_first;
162 FATAL("Endpoint not in endpoint's list.\n");
169 * trace header for application
171 void EndpointAppPBX::trace_header(const char *name, int direction)
175 char msgtext[sizeof(_trace.name)];
179 /* init trace with given values */
182 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
186 ea_endpoint->ep_serial,
193 /* set new endpoint state
195 void EndpointAppPBX::new_state(int state)
198 if (e_state != state) {
199 trace_header("NEW STATE", DIRECTION_NONE);
200 add_trace("state", "old", "%s", state_name[e_state]);
201 add_trace("state", "new", "%s", state_name[state]);
209 /* release join and port (as specified)
211 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force)
213 struct port_list *portlist;
214 struct lcr_msg *message;
217 /* message to test call */
218 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
220 /* if a release is pending */
221 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
222 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
223 if (ea_endpoint->ep_join_id) {
224 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
225 message->param.disconnectinfo.cause = joincause;
226 message->param.disconnectinfo.location = joinlocation;
227 message_put(message);
228 ea_endpoint->ep_join_id = 0;
232 if (release != RELEASE_PORT_JOINONLY) {
234 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
239 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
240 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
241 while((portlist = ea_endpoint->ep_portlist)) {
242 if (portlist->port_id) {
243 SPRINT(cause, "cause_%02x", portcause);
244 set_tone(portlist, cause);
245 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
246 message->param.disconnectinfo.cause = portcause;
247 message->param.disconnectinfo.location = portlocation;
248 message->param.disconnectinfo.force = force; // set, if port should release imediately
249 message_put(message);
250 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
252 ea_endpoint->free_portlist(portlist);
255 /* if callback is enabled, call back with the given caller id */
256 if (e_callback_timeout.active) {
257 /* reset some stuff */
258 new_state(EPOINT_STATE_IDLE);
259 memset(&e_connectinfo, 0, sizeof(struct connect_info));
260 memset(&e_redirinfo, 0, sizeof(struct redir_info));
261 e_start = e_stop = 0;
262 e_ruleset = ruleset_main;
264 e_rule = e_ruleset->rule_first;
266 unsched_timer(&e_action_timeout);
267 unsched_timer(&e_match_timeout);
268 unsched_timer(&e_cfnr_timeout);
269 unsched_timer(&e_cfnr_call_timeout);
270 e_match_to_action = NULL;
272 e_extdialing = e_dialinginfo.id;
278 e_multipoint_cause = 0;
279 e_multipoint_location = 0;
280 e_dialing_queue[0] = '\0';
283 e_crypt_state = CM_ST_NULL;
284 e_crypt_keyengine_busy = 0;
285 e_crypt_info[0] = '\0';
290 e_tx_state = NOTIFY_STATE_ACTIVE;
291 e_rx_state = NOTIFY_STATE_ACTIVE;
292 e_join_cause = e_join_location = 0;
294 /* the caller info of the callback user */
295 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
296 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
297 /* create dialing by callerinfo */
298 if (e_ext.number[0] && e_extension_interface[0]) {
299 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
300 /* create callback to the current terminal */
301 SCPY(e_dialinginfo.id, e_ext.number);
302 SCPY(e_dialinginfo.interfaces, e_extension_interface);
303 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
304 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
307 SCPY(e_dialinginfo.id, e_cbto);
309 /* numberrize caller id and use it to dial to the callback */
310 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
312 e_dialinginfo.itype = INFO_ITYPE_ISDN;
313 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
314 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
319 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
320 if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */
321 trigger_work(&ea_endpoint->ep_delete);
327 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
328 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
330 PDEBUG(DEBUG_EPOINT, "id='%s' ntype=%d present=%d screen=%d extension='%s' name='%s'\n", (id)?id:"NULL", (ntype)?*ntype:-1, (present)?*present:-1, (screen)?*screen:-1, (extension)?extension:"NULL", (name)?name:"NULL");
332 /* caller id is not restricted, so we do nothing */
333 if (*present != INFO_PRESENT_RESTRICTED)
336 /* only extensions are restricted */
340 /* if we enabled anonymouse ignore */
341 if (ext->anon_ignore)
344 /* else we remove the caller id */
348 *ntype = INFO_NTYPE_UNKNOWN;
350 // *screen = INFO_SCREEN_USER;
351 // maybe we should not make voip address anonymous
354 // maybe it's no fraud to present extension id
356 // extension[0] = '\0';
361 /* used display message to display callerid as available */
362 char *EndpointAppPBX::apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name)
364 static char display[81];
367 const char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
369 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) id='%s' itype=%d ntype=%d present=%d screen=%d extension='%s' name='%s'\n", ea_endpoint->ep_serial, (id)?id:"NULL", itype, ntype, present, screen, (extension)?extension:"NULL", (name)?name:"NULL");
378 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
380 /* internal extension's caller id */
381 if (extension[0] && e_ext.display_int) {
383 SCAT(display, extension);
386 if (itype == INFO_ITYPE_VBOX)
387 SCAT(display, "(vbox)");
389 SCAT(display, "(int)");
392 /* external caller id */
393 if (!extension[0] && e_ext.display_ext) {
396 if (present == INFO_PRESENT_RESTRICTED)
397 SCAT(display, "anonymous");
399 SCAT(display, "unknown");
406 /* display if callerid is anonymouse but available due anon-ignore */
407 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED) {
409 SCAT(display, "unknown");
412 SCAT(display, " anon");
415 /* display if callerid is anonymouse but available due anon-ignore */
416 if (e_ext.display_fake && screen==INFO_SCREEN_USER && ntype!=INFO_NTYPE_NOTPRESENT) {
419 if (present == INFO_PRESENT_RESTRICTED)
420 SCAT(display, "anonymous");
422 SCAT(display, "unknown");
427 SCAT(display, " fake");
431 if (name[0] && e_ext.display_name) {
432 if (!display[0] && cid[0])
443 * uses the current state to notify activity
445 void EndpointAppPBX::notify_active(void)
447 struct port_list *portlist = ea_endpoint->ep_portlist;
448 struct lcr_msg *message;
452 case NOTIFY_STATE_ACTIVE:
453 /* we are already active, so we don't do anything */
456 case NOTIFY_STATE_SUSPEND:
457 notify = INFO_NOTIFY_USER_RESUMED;
459 set_tone(portlist, NULL);
460 portlist = portlist->next;
462 portlist = ea_endpoint->ep_portlist;
465 case NOTIFY_STATE_HOLD:
466 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
468 set_tone(portlist, NULL);
469 portlist = portlist->next;
471 portlist = ea_endpoint->ep_portlist;
474 case NOTIFY_STATE_CONFERENCE:
475 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
477 set_tone(portlist, NULL);
478 portlist = portlist->next;
480 portlist = ea_endpoint->ep_portlist;
484 PERROR("unknown e_tx_state = %d\n", e_tx_state);
489 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
490 message->param.notifyinfo.notify = notify;
491 message_put(message);
492 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
493 portlist = portlist->next;
499 * keypad functions during call. one example to use this is to put a call on hold or start a conference
501 void EndpointAppPBX::keypad_function(char digit)
504 /* we must be in a call, in order to send messages to the call */
505 if (e_ext.number[0] == '\0') {
506 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
511 /* join conference */
513 if (ea_endpoint->ep_join_id == 0) {
514 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
517 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
524 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
528 /* crypt key-exchange */
530 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
536 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
542 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
547 /* set tone pattern for port */
548 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
550 struct lcr_msg *message;
555 /* store for suspended processes */
559 if (e_join_pattern /* pattern are provided */
560 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
561 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
562 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
563 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
564 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
565 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
566 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
567 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
568 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
569 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
570 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
571 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
576 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
577 SCPY(message->param.tone.dir, e_ext.tones_dir);
578 SCPY(message->param.tone.name, tone);
579 message_put(message);
580 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
582 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
588 /* outgoing setup to port(s)
589 * ports will be created and a setup is sent if everything is ok. otherwhise
590 * the endpoint is destroyed.
592 void EndpointAppPBX::out_setup(int cfnr)
594 struct dialing_info dialinginfo;
596 struct port_list *portlist;
597 struct lcr_msg *message;
599 int cause = CAUSE_RESSOURCEUNAVAIL;
602 struct interface *interface;
604 struct mISDNport *mISDNport;
608 class EndpointAppPBX *atemp;
609 // char allowed_ports[256];
611 char ifname[sizeof(e_ext.interfaces)],
613 struct port_settings port_settings;
616 struct admin_list *admin;
619 int mode = B_MODE_TRANSPARENT;
621 /* set bchannel mode */
622 mode = e_capainfo.source_mode;
624 /* create settings for creating port */
625 memset(&port_settings, 0, sizeof(port_settings));
627 SCPY(port_settings.tones_dir, e_ext.tones_dir);
629 SCPY(port_settings.tones_dir, options.tones_dir);
630 port_settings.no_seconds = e_ext.no_seconds;
632 /* NOTE: currently the try_card feature is not supported. it should be used later to try another card, if the outgoing call fails on one port */
634 /* check what dialinginfo.itype we got */
635 switch(e_dialinginfo.itype) {
636 /* *********************** call to extension or vbox */
637 case INFO_ITYPE_ISDN_EXTENSION:
638 /* check if we deny incoming calls when we use an extension */
639 if (e_ext.noknocking) {
640 atemp = apppbx_first;
643 if (!strcmp(atemp->e_ext.number, e_ext.number))
648 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
649 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
650 return; /* must exit here */
653 /* FALL THROUGH !!!! */
654 case INFO_ITYPE_VBOX:
655 /* get dialed extension's info */
656 // SCPY(exten, e_dialinginfo.id);
657 // if (strchr(exten, ','))
658 // *strchr(exten, ',') = '\0';
659 // if (!read_extension(&e_ext, exten))
660 if (!read_extension(&e_ext, e_dialinginfo.id)) {
661 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
662 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
663 return; /* must exit here */
665 e_dialinginfo.sending_complete = 1;
667 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
668 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
673 /* string from unconditional call forward (cfu) */
676 /* present to forwarded party */
677 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
678 e_callerinfo.present = INFO_PRESENT_ALLOWED;
680 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
684 /* string from busy call forward (cfb) */
687 class EndpointAppPBX *checkapp = apppbx_first;
689 if (checkapp != this) { /* any other endpoint except our own */
690 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
691 /* present to forwarded party */
692 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
693 e_callerinfo.present = INFO_PRESENT_ALLOWED;
695 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
699 checkapp = checkapp->next;
703 /* string from no-response call forward (cfnr) */
706 /* when cfnr is done, out_setup() will setup the call */
708 /* present to forwarded party */
709 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
710 e_callerinfo.present = INFO_PRESENT_ALLOWED;
714 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
715 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
716 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
717 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) setting time for call-forward-busy to %s with delay %ld.\n", ea_endpoint->ep_serial, e_ext.cfnr, e_ext.cfnr_delay);
721 /* call to all internal interfaces */
722 p = e_ext.interfaces;
723 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
727 while(*p!=',' && *p!='\0')
732 /* search interface */
733 interface = hunt_interface(ifname);
735 trace_header("INTERFACE (not found)", DIRECTION_NONE);
736 add_trace("interface", NULL, "%s", ifname);
740 /* found interface */
741 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
743 if (interface->gsm_bs) {
744 SPRINT(portname, "%s-%d-out", interface->name, 0);
745 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
746 earlyb = (interface->is_earlyb == IS_YES);
750 if (interface->gsm_ms) {
751 SPRINT(portname, "%s-%d-out", interface->name, 0);
752 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
753 earlyb = (interface->is_earlyb == IS_YES);
757 if (interface->sip) {
758 SPRINT(portname, "%s-%d-out", interface->name, 0);
759 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
760 earlyb = (interface->is_earlyb == IS_YES);
765 /* hunt for mISDNport and create Port */
766 mISDNport = hunt_port(ifname, &channel);
768 trace_header("INTERFACE (busy)", DIRECTION_NONE);
769 add_trace("interface", NULL, "%s", ifname);
774 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
777 port = ss5_hunt_line(mISDNport);
780 if (mISDNport->ifport->remote) {
783 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
788 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
789 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
793 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
795 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
796 earlyb = mISDNport->earlyb;
798 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
799 add_trace("interface", NULL, "%s", ifname);
805 FATAL("Failed to create Port instance\n");
806 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
807 memset(&dialinginfo, 0, sizeof(dialinginfo));
808 SCPY(dialinginfo.id, e_dialinginfo.id);
809 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
810 dialinginfo.ntype = e_dialinginfo.ntype;
811 /* create port_list relation */
812 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
814 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
816 goto check_anycall_intern;
819 if (e_callerinfo.id[0] && e_ext.display_name) {
820 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
822 SCPY(e_callerinfo.name, dirname);
824 // dss1 = (class Pdss1 *)port;
826 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
827 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
828 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
829 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
830 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
831 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
832 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
833 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
834 //terminal if (e_dialinginfo.id)
835 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
836 /* handle restricted caller ids */
837 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
838 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
839 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
840 /* display callerid if desired for extension */
841 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
842 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
843 /* use cnip, if enabld */
844 // if (!e_ext.centrex)
845 // message->param.setup.callerinfo.name[0] = '\0';
846 /* screen clip if prefix is required */
847 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
848 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
849 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
850 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
852 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
853 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
854 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
855 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
857 /* use internal caller id */
858 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
859 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
860 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
861 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
863 message_put(message);
864 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
868 /* string from parallel call forward (cfp) */
871 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
872 e_callerinfo.present = INFO_PRESENT_ALLOWED;
873 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
877 vbox_only: /* entry point for answering machine only */
878 cfu_only: /* entry point for cfu */
879 cfb_only: /* entry point for cfb */
880 cfnr_only: /* entry point for cfnr */
881 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
885 /* only if vbox should be dialed, and terminal is given */
886 if (!strcmp(p, "vbox") && e_ext.number[0]) {
887 /* go to the end of p */
890 /* answering vbox call */
891 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
893 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
894 FATAL("No memory for VBOX Port instance\n");
895 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
896 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
899 while(*p!=',' && *p!='\0')
904 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
906 /* hunt for mISDNport and create Port */
907 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
909 /* creating EXTERNAL port*/
910 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
913 port = ss5_hunt_line(mISDNport);
916 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
918 FATAL("No memory for Port instance\n");
919 earlyb = mISDNport->earlyb;
924 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
925 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
930 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
931 goto check_anycall_intern;
933 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
934 memset(&dialinginfo, 0, sizeof(dialinginfo));
935 SCPY(dialinginfo.id, cfp);
936 dialinginfo.itype = INFO_ITYPE_ISDN;
937 dialinginfo.ntype = e_dialinginfo.ntype;
938 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
940 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
942 goto check_anycall_intern;
944 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
945 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
946 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
947 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
948 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
949 /* if clip is hidden */
950 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
951 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
952 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
953 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
954 message->param.setup.callerinfo.present = e_ext.callerid_present;
955 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
957 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
958 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
959 //terminal if (e_dialinginfo.id)
960 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
961 /* handle restricted caller ids */
962 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
963 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
964 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
965 /* display callerid if desired for extension */
966 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
967 message_put(message);
968 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
972 check_anycall_intern:
973 /* now we have all ports created */
975 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
977 if (!ea_endpoint->ep_join_id)
979 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
980 return; /* must exit here */
984 /* *********************** external call */
986 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
987 /* call to extenal interfaces */
988 if (e_dialinginfo.keypad[0])
989 p = e_dialinginfo.keypad;
991 p = e_dialinginfo.id;
995 while(*p!=',' && *p!='\0')
1000 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1001 /* search interface */
1002 interface = hunt_interface(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL);
1004 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1005 add_trace("interface", NULL, "%s", ifname);
1007 goto check_anycall_extern;
1009 /* found interface */
1011 if (interface->gsm_bs) {
1012 SPRINT(portname, "%s-%d-out", interface->name, 0);
1013 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1014 earlyb = (interface->is_earlyb == IS_YES);
1018 if (interface->gsm_ms) {
1019 SPRINT(portname, "%s-%d-out", interface->name, 0);
1020 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1021 earlyb = (interface->is_earlyb == IS_YES);
1025 if (interface->sip) {
1026 SPRINT(portname, "%s-%d-out", interface->name, 0);
1027 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1028 earlyb = (interface->is_earlyb == IS_YES);
1033 /* hunt for mISDNport and create Port */
1034 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1036 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1037 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1039 goto check_anycall_extern;
1041 /* creating EXTERNAL port*/
1042 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1045 port = ss5_hunt_line(mISDNport);
1048 if (mISDNport->ifport->remote) {
1049 admin = admin_first;
1051 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1053 admin = admin->next;
1056 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1057 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1061 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1063 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1064 earlyb = mISDNport->earlyb;
1066 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
1067 add_trace("interface", NULL, "%s", ifname);
1073 FATAL("No memory for Port instance\n");
1074 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1075 memset(&dialinginfo, 0, sizeof(dialinginfo));
1076 if (e_dialinginfo.keypad[0])
1077 SCPY(dialinginfo.keypad, number);
1079 SCPY(dialinginfo.id, number);
1080 dialinginfo.itype = INFO_ITYPE_ISDN;
1081 dialinginfo.ntype = e_dialinginfo.ntype;
1082 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1083 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1085 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1087 goto check_anycall_extern;
1089 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1090 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1091 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1092 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1093 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1094 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1095 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1096 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1097 //terminal if (e_dialinginfo.id)
1098 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1099 /* handle restricted caller ids */
1100 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1101 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1102 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1103 /* display callerid if desired for extension */
1104 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
1105 message_put(message);
1106 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1110 check_anycall_extern:
1111 /* now we have all ports created */
1113 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1115 if (!ea_endpoint->ep_join_id)
1117 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1118 return; /* must exit here */
1125 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1127 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1129 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1132 unsched_timer(&ea->e_redial_timeout);
1133 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1134 ea->e_multipoint_cause = 0;
1135 ea->e_multipoint_location = 0;
1136 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1137 ea->e_join_pattern = 0;
1138 ea->process_dialing(1);
1139 /* we must exit, because our endpoint might be gone */
1144 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1146 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1148 if (!ea->e_action) {
1149 unsched_timer(&ea->e_redial_timeout);
1150 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1151 ea->process_dialing(0);
1152 /* we must exit, because our endpoint might be gone */
1158 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1160 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1162 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1164 ea->new_state(EPOINT_STATE_OUT_SETUP);
1165 /* call special setup routine */
1171 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1173 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1175 /* leave power dialing on */
1176 ea->e_powerdial_on = 1;
1177 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1180 ea->e_ruleset = ruleset_main;
1182 ea->e_rule = ea->e_ruleset->rule_first;
1183 ea->e_action = NULL;
1184 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1185 ea->process_dialing(0);
1190 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1192 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1193 struct port_list *portlist;
1194 struct lcr_msg *message;
1196 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1198 /* release all ports */
1199 while((portlist = ea->ea_endpoint->ep_portlist)) {
1200 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1201 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1202 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1203 message_put(message);
1204 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1205 ea->ea_endpoint->free_portlist(portlist);
1208 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1209 message->param.audiopath = 0;
1210 message_put(message);
1211 /* indicate no patterns */
1212 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1213 message_put(message);
1214 /* set setup state, since we have no response from the new join */
1215 ea->new_state(EPOINT_STATE_OUT_SETUP);
1220 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1222 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1224 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr);
1230 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1232 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1234 if (ea->e_state == EPOINT_STATE_IDLE) {
1235 /* epoint is idle, check callback */
1236 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1237 ea->new_state(EPOINT_STATE_OUT_SETUP);
1244 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1246 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1248 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1249 struct port_list *portlist;
1251 ea->e_ruleset = ruleset_main;
1253 ea->e_rule = ea->e_ruleset->rule_first;
1254 ea->e_action = NULL;
1255 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1256 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1258 ea->e_connectedmode = 0;
1260 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1261 portlist = ea->ea_endpoint->ep_portlist;
1263 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1264 ea->set_tone(portlist, "cause_10");
1271 /* doing a hookflash */
1272 void EndpointAppPBX::hookflash(void)
1277 /* be sure that we are active */
1279 e_tx_state = NOTIFY_STATE_ACTIVE;
1281 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1283 if (ea_endpoint->ep_use > 1) {
1284 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1287 /* dialtone after pressing the hash key */
1288 process_hangup(e_join_cause, e_join_location);
1289 e_multipoint_cause = 0;
1290 e_multipoint_location = 0;
1291 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1293 port->set_echotest(0);
1295 if (ea_endpoint->ep_join_id) {
1296 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1298 e_ruleset = ruleset_main;
1300 e_rule = e_ruleset->rule_first;
1302 new_state(EPOINT_STATE_IN_OVERLAP);
1303 e_connectedmode = 1;
1304 SCPY(e_dialinginfo.id, e_ext.prefix);
1305 e_extdialing = e_dialinginfo.id;
1307 if (e_dialinginfo.id[0]) {
1308 set_tone(ea_endpoint->ep_portlist, "dialing");
1311 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1319 /* messages from port
1321 /* port MESSAGE_SETUP */
1322 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1324 struct lcr_msg *message;
1326 int writeext; /* flags need to write extension after modification */
1329 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1331 portlist->port_type = param->setup.port_type;
1332 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1333 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1334 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1335 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1336 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
1338 /* convert (inter-)national number type */
1339 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1340 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1342 // e_dtmf = param->setup.dtmf;
1343 /* screen incoming caller id */
1344 if (e_callerinfo.interface[0]) {
1345 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface);
1346 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
1347 do_screen(0, e_redirinfo.id, sizeof(e_redirinfo.id), &e_redirinfo.ntype, &e_redirinfo.present, e_callerinfo.interface);
1350 /* process extension */
1351 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1352 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1353 /* port makes call from extension */
1354 SCPY(e_callerinfo.extension, e_callerinfo.id);
1355 SCPY(e_ext.number, e_callerinfo.extension);
1356 SCPY(e_extension_interface, e_callerinfo.interface);
1358 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1361 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1362 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1364 /* get extension's info about caller */
1365 if (!read_extension(&e_ext, e_ext.number)) {
1366 /* extension doesn't exist */
1367 trace_header("EXTENSION (not created)", DIRECTION_IN);
1368 add_trace("extension", NULL, "%s", e_ext.number);
1370 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1371 new_state(EPOINT_STATE_OUT_DISCONNECT);
1372 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1373 e_ext.number[0] = '\0'; /* no terminal */
1378 /* put prefix (next) in front of e_dialinginfo.id */
1379 if (e_ext.next[0]) {
1380 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1381 SCPY(e_dialinginfo.id, buffer);
1382 e_ext.next[0] = '\0';
1384 } else if (e_ext.prefix[0]) {
1385 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1386 SCPY(e_dialinginfo.id, buffer);
1389 /* screen caller id by extension's config */
1390 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1392 SCPY(e_callerinfo.name, e_ext.name);
1393 /* use caller id (or if exist: id_next_call) for this call */
1394 if (e_ext.id_next_call_present >= 0) {
1395 SCPY(e_callerinfo.id, e_ext.id_next_call);
1396 /* if we restrict the pesentation */
1397 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1398 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1399 else e_callerinfo.present = e_ext.id_next_call_present;
1400 e_callerinfo.ntype = e_ext.id_next_call_type;
1401 e_ext.id_next_call_present = -1;
1404 SCPY(e_callerinfo.id, e_ext.callerid);
1405 /* if we restrict the pesentation */
1406 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1407 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1408 else e_callerinfo.present = e_ext.callerid_present;
1409 e_callerinfo.ntype = e_ext.callerid_type;
1411 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1413 /* extension is written */
1415 write_extension(&e_ext, e_ext.number);
1417 /* set volume of rx and tx */
1418 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1419 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1420 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1421 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1422 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1423 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1424 message_put(message);
1427 /* start recording if enabled */
1428 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1429 /* check if we are a terminal */
1430 if (e_ext.number[0] == '\0')
1431 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1433 port = find_port_id(portlist->port_id);
1435 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1439 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1440 /* no terminal identification */
1441 e_ext.number[0] = '\0';
1442 e_extension_interface[0] = '\0';
1443 memset(&e_ext, 0, sizeof(e_ext));
1444 e_ext.rights = 4; /* right to dial internat */
1448 e_ruleset = ruleset_main;
1450 e_rule = e_ruleset->rule_first;
1452 e_extdialing = e_dialinginfo.id;
1453 new_state(EPOINT_STATE_IN_SETUP);
1454 if (e_dialinginfo.id[0]) {
1455 set_tone(portlist, "dialing");
1457 if (e_ext.number[0])
1458 set_tone(portlist, "dialpbx");
1460 set_tone(portlist, "dialtone");
1463 if (e_state == EPOINT_STATE_IN_SETUP) {
1464 /* request MORE info, if not already at higher state */
1465 new_state(EPOINT_STATE_IN_OVERLAP);
1466 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1467 message_put(message);
1468 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1472 /* port MESSAGE_INFORMATION */
1473 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1475 struct lcr_msg *message;
1477 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1479 /* ignore information message without digit information */
1480 if (!param->information.id[0])
1485 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1487 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1492 /* if vbox_play is done, the information are just used as they come */
1494 if (e_action->index == ACTION_VBOX_PLAY) {
1495 /* concat dialing string */
1496 SCAT(e_dialinginfo.id, param->information.id);
1501 /* keypad when disconnect but in connected mode */
1502 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1503 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1504 /* processing keypad function */
1505 if (param->information.id[0] == '0') {
1511 /* keypad when connected */
1512 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1513 if (e_enablekeypad) {
1514 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1515 memcpy(&message->param, param, sizeof(union parameter));
1516 message_put(message);
1520 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1521 /* processing keypad function */
1522 if (param->information.id[0] == '0') {
1525 if (param->information.id[0])
1526 keypad_function(param->information.id[0]);
1528 if (e_ext.number[0])
1529 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1531 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1536 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1537 if (e_ext.number[0])
1538 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1540 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1544 if (!param->information.id[0])
1546 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1547 set_tone(portlist, "dialing");
1550 if (e_action->index==ACTION_OUTDIAL
1551 || e_action->index==ACTION_EXTERNAL
1552 || e_action->index==ACTION_REMOTE) {
1554 set_tone(portlist, "dialing");
1555 else if (!e_extdialing[0])
1556 set_tone(portlist, "dialing");
1558 /* concat dialing string */
1559 SCAT(e_dialinginfo.id, param->information.id);
1563 /* port MESSAGE_DTMF */
1564 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1567 struct lcr_msg *message;
1571 /* only if dtmf detection is enabled */
1573 trace_header("DTMF (disabled)", DIRECTION_IN);
1577 trace_header("DTMF", DIRECTION_IN);
1578 add_trace("digit", NULL, "%c", param->dtmf);
1582 NOTE: vbox is now handled due to overlap state
1583 /* if vbox_play is done, the dtmf digits are just used as they come */
1585 if (e_action->index == ACTION_VBOX_PLAY) {
1586 /* concat dialing string */
1587 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1588 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1589 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1592 /* continue to process *X# sequences */
1596 /* check for *X# sequence */
1597 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1598 if (e_enablekeypad) {
1599 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1600 memcpy(&message->param, param, sizeof(union parameter));
1601 message_put(message);
1604 if (e_dtmf_time+3 < now) {
1605 /* the last digit was too far in the past to be a sequence */
1606 if (param->dtmf == '*')
1607 /* only start is allowed in the sequence */
1612 /* we have a sequence of digits, see what we got */
1613 if (param->dtmf == '*')
1615 else if (param->dtmf>='0' && param->dtmf<='9') {
1616 /* we need to have a star before we receive the digit of the sequence */
1617 if (e_dtmf_last == '*')
1618 e_dtmf_last = param->dtmf;
1619 } else if (param->dtmf == '#') {
1621 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1622 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1623 if (e_dtmf_last == '0') {
1627 /* processing keypad function */
1629 keypad_function(e_dtmf_last);
1635 /* set last time of dtmf */
1640 /* check for ## hookflash during dialing */
1642 if (e_action->index==ACTION_PASSWORD
1643 || e_action->index==ACTION_PASSWORD_WRITE)
1645 if (param->dtmf=='#') { /* current digit is '#' */
1646 if (e_state==EPOINT_STATE_IN_DISCONNECT
1647 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1661 /* dialing using dtmf digit */
1662 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1663 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1664 set_tone(portlist, "dialing");
1666 /* concat dialing string */
1667 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1668 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1669 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1675 /* port MESSAGE_CRYPT */
1676 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1679 /* send crypt response to cryptman */
1680 if (param->crypt.type == CR_MESSAGE_IND)
1681 cryptman_msg2man(param->crypt.data, param->crypt.len);
1683 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1687 /* port MESSAGE_OVERLAP */
1688 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1690 struct lcr_msg *message;
1692 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1694 /* signal to call tool */
1695 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1697 if (e_dialing_queue[0] && portlist) {
1698 /* send what we have not dialed yet, because we had no setup complete */
1699 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1700 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1701 SCPY(message->param.information.id, e_dialing_queue);
1702 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1703 message_put(message);
1704 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1705 e_dialing_queue[0] = '\0';
1707 /* check if pattern is available */
1708 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1709 /* indicate patterns */
1710 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1711 message_put(message);
1713 /* connect audio, if not already */
1714 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1715 message->param.audiopath = 1;
1716 message_put(message);
1718 /* indicate no patterns */
1719 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1720 message_put(message);
1722 /* disconnect audio, if not already */
1723 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1724 message->param.audiopath = 0;
1725 message_put(message);
1727 new_state(EPOINT_STATE_OUT_OVERLAP);
1728 /* if we are in a join */
1729 if (ea_endpoint->ep_join_id) {
1730 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1731 memcpy(&message->param, param, sizeof(union parameter));
1732 message_put(message);
1736 /* port MESSAGE_PROCEEDING */
1737 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1739 struct lcr_msg *message;
1741 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1743 /* signal to call tool */
1744 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1746 e_state = EPOINT_STATE_OUT_PROCEEDING;
1747 /* check if pattern is availatle */
1748 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1749 /* indicate patterns */
1750 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1751 message_put(message);
1753 /* connect audio, if not already */
1754 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1755 message->param.audiopath = 1;
1756 message_put(message);
1758 /* indicate no patterns */
1759 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1760 message_put(message);
1762 /* disconnect audio, if not already */
1763 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1764 message->param.audiopath = 0;
1765 message_put(message);
1767 /* if we are in a call */
1768 if (ea_endpoint->ep_join_id) {
1769 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1770 memcpy(&message->param, param, sizeof(union parameter));
1771 message_put(message);
1775 /* port MESSAGE_ALERTING */
1776 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1778 struct lcr_msg *message;
1780 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1782 /* signal to call tool */
1783 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1786 // set_tone(portlist, "hold");
1788 new_state(EPOINT_STATE_OUT_ALERTING);
1789 /* check if pattern is available */
1790 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1791 /* indicate patterns */
1792 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1793 message_put(message);
1795 /* connect audio, if not already */
1796 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1797 message->param.audiopath = 1;
1798 message_put(message);
1800 /* indicate no patterns */
1801 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1802 message_put(message);
1804 /* disconnect audio, if not already */
1805 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1806 message->param.audiopath = 0;
1807 message_put(message);
1809 /* if we are in a call */
1810 if (ea_endpoint->ep_join_id) {
1811 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1812 memcpy(&message->param, param, sizeof(union parameter));
1813 message_put(message);
1817 /* port MESSAGE_CONNECT */
1818 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1820 struct lcr_msg *message;
1822 unsigned int port_id = portlist->port_id;
1823 struct port_list *tportlist;
1827 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1829 /* signal to call tool */
1830 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1832 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1833 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1834 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1835 tportlist = ea_endpoint->ep_portlist;
1836 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1837 tportlist = tportlist->next;
1838 if (tportlist->port_id == port_id)
1839 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1840 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1841 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1842 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1843 message_put(message);
1844 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1845 ea_endpoint->free_portlist(tportlist);
1847 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1852 if (e_callerinfo.interface[0])
1853 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface);
1855 /* screen connected name */
1857 SCPY(e_connectinfo.name, e_ext.name);
1859 /* add internal id to colp */
1860 SCPY(e_connectinfo.extension, e_ext.number);
1862 /* we store the connected port number */
1863 SCPY(e_extension_interface, e_connectinfo.interface);
1865 /* for internal and am calls, we get the extension's id */
1866 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1867 SCPY(e_connectinfo.id, e_ext.callerid);
1868 SCPY(e_connectinfo.extension, e_ext.number);
1869 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1870 e_connectinfo.ntype = e_ext.callerid_type;
1871 e_connectinfo.present = e_ext.callerid_present;
1873 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
1874 e_connectinfo.itype = INFO_ITYPE_VBOX;
1875 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1878 new_state(EPOINT_STATE_CONNECT);
1880 /* set volume of rx and tx */
1881 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1882 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1883 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1884 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1885 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1886 message_put(message);
1889 unsched_timer(&e_cfnr_timeout);
1890 unsched_timer(&e_cfnr_call_timeout);
1891 if (e_ext.number[0])
1892 e_dtmf = 1; /* allow dtmf */
1895 /* other calls with no caller id (or not available for the extension) and force colp */
1896 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
1897 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
1898 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
1899 /* external extension answered */
1900 port = find_port_id(portlist->port_id);
1902 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
1903 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1908 /* send connect to join */
1909 if (ea_endpoint->ep_join_id) {
1910 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1911 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1912 message_put(message);
1914 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1915 message->param.audiopath = 1;
1916 message_put(message);
1917 } else if (!e_adminid) {
1919 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
1920 SCPY(e_ext.number, e_cbcaller);
1921 new_state(EPOINT_STATE_IN_OVERLAP);
1922 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1924 /* get extension's info about terminal */
1925 if (!read_extension(&e_ext, e_ext.number)) {
1926 /* extension doesn't exist */
1927 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1928 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1929 new_state(EPOINT_STATE_OUT_DISCONNECT);
1930 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1934 /* put prefix in front of e_cbdialing */
1935 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
1936 SCPY(e_dialinginfo.id, buffer);
1937 e_dialinginfo.itype = INFO_ITYPE_ISDN;
1938 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1940 /* use caller id (or if exist: id_next_call) for this call */
1941 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1942 SCPY(e_callerinfo.extension, e_ext.number);
1943 if (e_ext.id_next_call_present >= 0) {
1944 SCPY(e_callerinfo.id, e_ext.id_next_call);
1945 e_callerinfo.present = e_ext.id_next_call_present;
1946 e_callerinfo.ntype = e_ext.id_next_call_type;
1947 e_ext.id_next_call_present = -1;
1948 /* extension is written */
1949 write_extension(&e_ext, e_ext.number);
1951 SCPY(e_callerinfo.id, e_ext.callerid);
1952 e_callerinfo.present = e_ext.callerid_present;
1953 e_callerinfo.ntype = e_ext.callerid_type;
1955 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1957 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
1960 /* check if caller id is NOT authenticated */
1961 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
1962 /* make call state to enter password */
1963 new_state(EPOINT_STATE_IN_OVERLAP);
1964 e_action = &action_password_write;
1965 unsched_timer(&e_match_timeout);
1966 e_match_to_action = NULL;
1967 e_dialinginfo.id[0] = '\0';
1968 e_extdialing = strchr(e_dialinginfo.id, '\0');
1969 schedule_timer(&e_password_timeout, 20, 0);
1972 /* incoming call (callback) */
1973 e_ruleset = ruleset_main;
1975 e_rule = e_ruleset->rule_first;
1977 e_extdialing = e_dialinginfo.id;
1978 if (e_dialinginfo.id[0]) {
1979 set_tone(portlist, "dialing");
1982 set_tone(portlist, "dialpbx");
1985 } else { /* testcall */
1986 set_tone(portlist, "hold");
1989 /* start recording if enabled, not when answering machine answers */
1990 if (param->connectinfo.itype!=INFO_ITYPE_VBOX && e_ext.number[0] && e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1991 /* check if we are a terminal */
1992 if (e_ext.number[0] == '\0')
1993 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1995 port = find_port_id(portlist->port_id);
1997 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2002 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2003 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2005 struct lcr_msg *message;
2007 unsigned int port_id = portlist->port_id;
2011 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2013 /* signal to call tool */
2014 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2016 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2017 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2018 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2023 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current multipoint cause %d location %d, received cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2024 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2025 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2027 /* check if we have more than one portlist relation and we just ignore the disconnect */
2028 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2029 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2030 portlist = ea_endpoint->ep_portlist;
2032 if (portlist->port_id == port_id)
2034 portlist = portlist->next;
2037 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2038 if (message_type != MESSAGE_RELEASE) {
2039 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2040 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2041 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2042 message_put(message);
2043 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2045 ea_endpoint->free_portlist(portlist);
2046 return; /* one relation removed */
2048 if (e_state == EPOINT_STATE_CONNECT) {
2049 /* use cause from port after connect */
2050 cause = param->disconnectinfo.cause;
2051 location = param->disconnectinfo.location;
2053 /* use multipoint cause if no connect yet */
2054 if (e_multipoint_cause) {
2055 cause = e_multipoint_cause;
2056 location = e_multipoint_location;
2058 cause = CAUSE_NOUSER;
2059 location = LOCATION_PRIVATE_LOCAL;
2063 unsched_timer(&e_cfnr_timeout);
2064 unsched_timer(&e_cfnr_call_timeout);
2066 /* process hangup */
2067 process_hangup(e_join_cause, e_join_location);
2068 e_multipoint_cause = 0;
2069 e_multipoint_location = 0;
2071 if (message_type == MESSAGE_DISCONNECT) {
2072 /* tone to disconnected end */
2073 SPRINT(buffer, "cause_%02x", cause);
2074 if (ea_endpoint->ep_portlist)
2075 set_tone(ea_endpoint->ep_portlist, buffer);
2077 new_state(EPOINT_STATE_IN_DISCONNECT);
2080 if (ea_endpoint->ep_join_id) {
2081 int haspatterns = 0;
2082 /* check if pattern is available */
2083 if (ea_endpoint->ep_portlist)
2084 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2085 if (joinpbx_countrelations(ea_endpoint->ep_join_id)==2 // we must count relations, in order not to disturb the conference ; NOTE: asterisk always counts two, since it is a point to point call
2086 && message_type != MESSAGE_RELEASE) // if we release, we are done
2089 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2090 /* indicate patterns */
2091 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2092 message_put(message);
2093 /* connect audio, if not already */
2094 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2095 message->param.audiopath = 1;
2096 message_put(message);
2097 /* send disconnect */
2098 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2099 memcpy(&message->param, param, sizeof(union parameter));
2100 message_put(message);
2101 /* disable encryption if disconnected */
2102 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2105 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2109 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2112 if (message_type == MESSAGE_RELEASE)
2113 ea_endpoint->free_portlist(portlist);
2114 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2115 return; /* must exit here */
2118 /* port MESSAGE_TIMEOUT */
2119 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2123 trace_header("TIMEOUT", DIRECTION_IN);
2124 message_type = MESSAGE_DISCONNECT;
2125 switch (param->state) {
2126 case PORT_STATE_OUT_SETUP:
2127 case PORT_STATE_OUT_OVERLAP:
2128 add_trace("state", NULL, "outgoing setup/dialing");
2130 /* no user responding */
2131 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2132 return; /* must exit here */
2134 case PORT_STATE_IN_SETUP:
2135 case PORT_STATE_IN_OVERLAP:
2136 add_trace("state", NULL, "incoming setup/dialing");
2137 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2138 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2141 case PORT_STATE_OUT_PROCEEDING:
2142 add_trace("state", NULL, "outgoing proceeding");
2144 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2145 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2146 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2147 return; /* must exit here */
2149 case PORT_STATE_IN_PROCEEDING:
2150 add_trace("state", NULL, "incoming proceeding");
2151 param->disconnectinfo.cause = CAUSE_NOUSER;
2152 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2155 case PORT_STATE_OUT_ALERTING:
2156 add_trace("state", NULL, "outgoing alerting");
2158 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2159 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2160 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2161 return; /* must exit here */
2163 case PORT_STATE_CONNECT:
2164 add_trace("state", NULL, "connect");
2166 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2167 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2168 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2169 return; /* must exit here */
2171 case PORT_STATE_IN_ALERTING:
2172 add_trace("state", NULL, "incoming alerting");
2173 param->disconnectinfo.cause = CAUSE_NOANSWER;
2174 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2177 case PORT_STATE_IN_DISCONNECT:
2178 case PORT_STATE_OUT_DISCONNECT:
2179 add_trace("state", NULL, "disconnect");
2181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2182 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2183 return; /* must exit here */
2186 param->disconnectinfo.cause = 31; /* normal unspecified */
2187 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2190 /* release call, disconnect isdn */
2192 new_state(EPOINT_STATE_OUT_DISCONNECT);
2193 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2194 SCPY(e_tone, cause);
2196 set_tone(portlist, cause);
2197 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2198 portlist = portlist->next;
2200 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2203 /* port MESSAGE_NOTIFY */
2204 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2206 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2208 struct lcr_msg *message;
2209 const char *logtext = "";
2212 /* signal to call tool */
2213 admin_call_response(e_adminid, ADMIN_CALL_NOTIFY, numberrize_callerinfo(param->notifyinfo.id,param->notifyinfo.ntype, options.national, options.international), 0, 0, param->notifyinfo.notify);
2214 if (param->notifyinfo.notify) {
2215 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2218 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2219 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2220 case INFO_NOTIFY_REMOTE_HOLD:
2221 case INFO_NOTIFY_USER_SUSPENDED:
2222 /* tell call about it */
2223 if (ea_endpoint->ep_join_id) {
2224 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2225 message->param.audiopath = 0;
2226 message_put(message);
2230 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2231 case INFO_NOTIFY_USER_RESUMED:
2232 /* set volume of rx and tx */
2233 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2234 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2236 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2237 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2238 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2239 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2240 message_put(message);
2242 /* set current tone */
2244 set_tone(portlist, e_tone);
2245 /* tell call about it */
2246 if (ea_endpoint->ep_join_id) {
2247 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2248 message->param.audiopath = 1;
2249 message_put(message);
2254 /* get name of notify */
2255 switch(param->notifyinfo.notify) {
2260 logtext = "USER_SUSPENDED";
2263 logtext = "BEARER_SERVICE_CHANGED";
2266 logtext = "USER_RESUMED";
2269 logtext = "CONFERENCE_ESTABLISHED";
2272 logtext = "CONFERENCE_DISCONNECTED";
2275 logtext = "OTHER_PARTY_ADDED";
2278 logtext = "ISOLATED";
2281 logtext = "REATTACHED";
2284 logtext = "OTHER_PARTY_ISOLATED";
2287 logtext = "OTHER_PARTY_REATTACHED";
2290 logtext = "OTHER_PARTY_SPLIT";
2293 logtext = "OTHER_PARTY_DISCONNECTED";
2296 logtext = "CONFERENCE_FLOATING";
2299 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2302 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2305 logtext = "CALL_IS_A_WAITING_CALL";
2308 logtext = "DIVERSION_ACTIVATED";
2311 logtext = "RESERVED_CT_1";
2314 logtext = "RESERVED_CT_2";
2317 logtext = "REVERSE_CHARGING";
2320 logtext = "REMOTE_HOLD";
2323 logtext = "REMOTE_RETRIEVAL";
2326 logtext = "CALL_IS_DIVERTING";
2329 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2334 /* notify call if available */
2335 if (ea_endpoint->ep_join_id) {
2336 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2337 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2338 message_put(message);
2343 /* port MESSAGE_PROGRESS */
2344 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2346 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2348 struct lcr_msg *message;
2350 /* signal to call tool */
2351 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2353 /* send progress to call if available */
2354 if (ea_endpoint->ep_join_id) {
2355 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2356 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2357 message_put(message);
2362 /* port MESSAGE_FACILITY */
2363 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2365 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2367 struct lcr_msg *message;
2369 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2370 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2371 message_put(message);
2374 /* port MESSAGE_SUSPEND */
2375 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2376 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2378 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2380 /* epoint is now parked */
2381 ea_endpoint->ep_park = 1;
2382 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2383 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2385 /* remove port relation */
2386 ea_endpoint->free_portlist(portlist);
2389 /* port MESSAGE_RESUME */
2390 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2391 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2393 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2395 /* epoint is now resumed */
2396 ea_endpoint->ep_park = 0;
2400 /* port MESSAGE_ENABLEKEYPAD */
2401 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2403 struct lcr_msg *message;
2405 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2407 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2408 memcpy(&message->param, param, sizeof(union parameter));
2409 message_put(message);
2413 /* port sends message to the endpoint
2415 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2417 struct port_list *portlist;
2419 portlist = ea_endpoint->ep_portlist;
2421 if (port_id == portlist->port_id)
2423 portlist = portlist->next;
2426 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) warning: port is not related to this endpoint. This may happen, if port has been released after the message was created.\n", ea_endpoint->ep_serial);
2430 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2431 switch(message_type) {
2432 case MESSAGE_TONE_EOF: /* tone is end of file */
2433 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2435 if (e_action->index == ACTION_VBOX_PLAY) {
2438 if (e_action->index == ACTION_EFI) {
2444 case MESSAGE_TONE_COUNTER: /* counter info received */
2445 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received counter information: %d / %d seconds after start of tone.\n", ea_endpoint->ep_serial, param->counter.current, param->counter.max);
2447 if (e_action->index == ACTION_VBOX_PLAY) {
2448 e_vbox_counter = param->counter.current;
2449 if (param->counter.max >= 0)
2450 e_vbox_counter_max = param->counter.max;
2454 /* PORT sends SETUP message */
2456 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call from callerid=%s, dialing=%s\n", ea_endpoint->ep_serial, param->setup.callerinfo.id, param->setup.dialinginfo.id);
2457 if (e_state!=EPOINT_STATE_IDLE) {
2458 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2461 port_setup(portlist, message_type, param);
2464 /* PORT sends INFORMATION message */
2465 case MESSAGE_INFORMATION: /* additional digits received */
2466 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call dialing more=%s (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, param->information.id, e_ext.number, e_callerinfo.id);
2467 port_information(portlist, message_type, param);
2470 /* PORT sends FACILITY message */
2471 case MESSAGE_FACILITY:
2472 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2473 port_facility(portlist, message_type, param);
2476 /* PORT sends DTMF message */
2477 case MESSAGE_DTMF: /* dtmf digits received */
2478 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf digit=%c (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, param->dtmf, e_ext.number, e_callerinfo.id);
2479 port_dtmf(portlist, message_type, param);
2482 /* PORT sends CRYPT message */
2483 case MESSAGE_CRYPT: /* crypt response received */
2484 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2485 port_crypt(portlist, message_type, param);
2488 /* PORT sends MORE message */
2489 case MESSAGE_OVERLAP:
2490 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) outgoing call is accepted [overlap dialing] (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2491 if (e_state != EPOINT_STATE_OUT_SETUP) {
2492 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state (for port_list: another portlist might have changed the state already).\n", ea_endpoint->ep_serial);
2495 port_overlap(portlist, message_type, param);
2498 /* PORT sends PROCEEDING message */
2499 case MESSAGE_PROCEEDING: /* port is proceeding */
2500 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) outgoing call is proceeding (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2501 if (e_state!=EPOINT_STATE_OUT_SETUP
2502 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2503 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in overlap state (for port_list: another portlist might have changed the state already).\n", ea_endpoint->ep_serial);
2506 port_proceeding(portlist, message_type, param);
2509 /* PORT sends ALERTING message */
2510 case MESSAGE_ALERTING:
2511 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) outgoing call is ringing (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2512 if (e_state!=EPOINT_STATE_OUT_SETUP
2513 && e_state!=EPOINT_STATE_OUT_OVERLAP
2514 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2515 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state (for port_list: another portlist might have changed the state already).\n", ea_endpoint->ep_serial);
2518 port_alerting(portlist, message_type, param);
2521 /* PORT sends CONNECT message */
2522 case MESSAGE_CONNECT:
2523 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) outgoing call connected to %s (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_connectinfo.id, e_ext.number, e_callerinfo.id);
2524 if (e_state!=EPOINT_STATE_OUT_SETUP
2525 && e_state!=EPOINT_STATE_OUT_OVERLAP
2526 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2527 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2528 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2531 port_connect(portlist, message_type, param);
2534 /* PORT sends DISCONNECT message */
2535 case MESSAGE_DISCONNECT: /* port is disconnected */
2536 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call disconnect with cause=%d location=%d (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, param->disconnectinfo.cause, param->disconnectinfo.location, e_ext.number, e_callerinfo.id);
2537 port_disconnect_release(portlist, message_type, param);
2540 /* PORT sends a RELEASE message */
2541 case MESSAGE_RELEASE: /* port releases */
2542 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) release with cause=%d location=%d (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, param->disconnectinfo.cause, param->disconnectinfo.location, e_ext.number, e_callerinfo.id);
2543 /* portlist is release at port_disconnect_release, thanx Paul */
2544 port_disconnect_release(portlist, message_type, param);
2547 /* PORT sends a TIMEOUT message */
2548 case MESSAGE_TIMEOUT:
2549 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received timeout (state=%d).\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->state);
2550 port_timeout(portlist, message_type, param);
2551 break; /* release */
2553 /* PORT sends a NOTIFY message */
2554 case MESSAGE_NOTIFY:
2555 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received notify.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2556 port_notify(portlist, message_type, param);
2559 /* PORT sends a PROGRESS message */
2560 case MESSAGE_PROGRESS:
2561 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received progress.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2562 port_progress(portlist, message_type, param);
2565 /* PORT sends a SUSPEND message */
2566 case MESSAGE_SUSPEND:
2567 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received suspend.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2568 port_suspend(portlist, message_type, param);
2569 break; /* suspend */
2571 /* PORT sends a RESUME message */
2572 case MESSAGE_RESUME:
2573 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received resume.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2574 port_resume(portlist, message_type, param);
2578 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2579 /* port assigns bchannel */
2580 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2581 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel message %d from port.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type);
2582 /* only one port is expected to be connected to bchannel */
2583 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2584 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2588 /* PORT requests DTMF */
2589 case MESSAGE_ENABLEKEYPAD:
2590 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') requests DTMF/KEYPAD.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2591 port_enablekeypad(portlist, message_type, param);
2596 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: %d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
2599 /* Note: this endpoint may be destroyed, so we MUST return */
2603 /* messages from join
2605 /* join MESSAGE_CRYPT */
2606 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2609 switch(param->crypt.type) {
2610 /* message from remote port to "crypt manager" */
2611 case CU_ACTK_REQ: /* activate key-exchange */
2612 case CU_ACTS_REQ: /* activate shared key */
2613 case CU_DACT_REQ: /* deactivate */
2614 case CU_INFO_REQ: /* request last info message */
2615 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2618 /* message from "crypt manager" to user */
2619 case CU_ACTK_CONF: /* key-echange done */
2620 case CU_ACTS_CONF: /* shared key done */
2621 case CU_DACT_CONF: /* deactivated */
2622 case CU_DACT_IND: /* deactivated */
2623 case CU_ERROR_IND: /* receive error message */
2624 case CU_INFO_IND: /* receive info message */
2625 case CU_INFO_CONF: /* receive info message */
2626 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2630 PERROR("EPOINT(%d) epoint with terminal '%s' (caller id '%s') unknown crypt message: '%d'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->crypt.type);
2635 /* join MESSAGE_INFORMATION */
2636 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2638 struct lcr_msg *message;
2643 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2644 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2645 message_put(message);
2646 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2647 portlist = portlist->next;
2651 /* join MESSAGE_FACILITY */
2652 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2654 struct lcr_msg *message;
2656 if (!e_ext.facility && e_ext.number[0]) {
2661 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2662 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2663 message_put(message);
2664 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2665 portlist = portlist->next;
2669 /* join MESSAGE_MORE */
2670 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2672 struct lcr_msg *message;
2674 new_state(EPOINT_STATE_IN_OVERLAP);
2677 if (e_join_pattern && e_ext.own_setup) {
2678 /* disconnect audio */
2679 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2680 message->param.audiopath = 0;
2681 message_put(message);
2683 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2684 if (e_dialinginfo.id[0])
2685 set_tone(portlist, "dialing");
2687 set_tone(portlist, "dialtone");
2690 if (e_dialinginfo.id[0]) {
2691 set_tone(portlist, "dialing");
2693 if (e_ext.number[0])
2694 set_tone(portlist, "dialpbx");
2696 set_tone(portlist, "dialtone");
2700 /* join MESSAGE_PROCEEDING */
2701 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2703 struct lcr_msg *message;
2705 new_state(EPOINT_STATE_IN_PROCEEDING);
2707 /* own proceeding tone */
2708 if (e_join_pattern) {
2709 /* connect / disconnect audio */
2710 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2711 if (e_ext.own_proceeding)
2712 message->param.audiopath = 0;
2714 message->param.audiopath = 1;
2715 message_put(message);
2717 // UCPY(e_join_tone, "proceeding");
2719 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2720 message_put(message);
2721 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2723 set_tone(portlist, "proceeding");
2726 /* join MESSAGE_ALERTING */
2727 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2729 struct lcr_msg *message;
2731 new_state(EPOINT_STATE_IN_ALERTING);
2733 /* own alerting tone */
2734 if (e_join_pattern) {
2735 /* connect / disconnect audio */
2736 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2737 if (e_ext.own_alerting)
2738 message->param.audiopath = 0;
2740 message->param.audiopath = 1;
2741 message_put(message);
2744 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2745 message_put(message);
2746 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2748 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2749 set_tone(portlist, "ringing");
2752 if (e_ext.number[0])
2753 set_tone(portlist, "ringpbx");
2755 set_tone(portlist, "ringing");
2757 if (e_ext.number[0])
2758 e_dtmf = 1; /* allow dtmf */
2761 /* join MESSAGE_CONNECT */
2762 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2764 struct lcr_msg *message;
2767 new_state(EPOINT_STATE_CONNECT);
2768 // UCPY(e_join_tone, "");
2770 if (e_ext.number[0])
2771 e_dtmf = 1; /* allow dtmf */
2774 unsched_timer(&e_powerdial_timeout);
2775 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2777 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2778 memcpy(&message->param, param, sizeof(union parameter));
2780 /* screen clip if prefix is required */
2781 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2782 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2783 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2784 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2787 /* use internal caller id */
2788 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2789 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2790 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2793 /* handle restricted caller ids */
2794 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);
2795 /* display callerid if desired for extension */
2796 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));
2798 /* use conp, if enabld */
2799 // if (!e_ext.centrex)
2800 // message->param.connectinfo.name[0] = '\0';
2803 message_put(message);
2804 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2806 set_tone(portlist, NULL);
2808 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2809 message->param.audiopath = 1;
2810 message_put(message);
2815 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2816 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2819 struct lcr_msg *message;
2820 struct port_list *portlist = NULL;
2824 /* be sure that we are active */
2826 e_tx_state = NOTIFY_STATE_ACTIVE;
2828 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2829 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2830 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2832 /* set time for power dialing */
2833 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2836 /* set redial tone */
2837 if (ea_endpoint->ep_portlist) {
2840 set_tone(ea_endpoint->ep_portlist, "redial");
2841 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') redialing in %d seconds\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, (int)e_powerdelay);
2842 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2843 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2844 new_state(EPOINT_STATE_IN_PROCEEDING);
2845 if (ea_endpoint->ep_portlist) {
2846 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2847 message_put(message);
2848 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2850 /* caused the error, that the first knock sound was not there */
2851 /* set_tone(portlist, "proceeding"); */
2853 /* send display of powerdialing */
2854 if (e_ext.display_dialing) {
2855 portlist = ea_endpoint->ep_portlist;
2857 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2859 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2861 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2862 message_put(message);
2863 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2864 portlist = portlist->next;
2874 if ((e_state!=EPOINT_STATE_CONNECT
2875 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2876 && e_state!=EPOINT_STATE_IN_OVERLAP
2877 && e_state!=EPOINT_STATE_IN_PROCEEDING
2878 && e_state!=EPOINT_STATE_IN_ALERTING)
2879 || !ea_endpoint->ep_portlist) { /* or no port */
2880 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2881 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2882 return; /* must exit here */
2885 if (!e_join_cause) {
2886 e_join_cause = param->disconnectinfo.cause;
2887 e_join_location = param->disconnectinfo.location;
2890 /* on release we need the audio again! */
2891 if (message_type == MESSAGE_RELEASE) {
2893 ea_endpoint->ep_join_id = 0;
2895 /* disconnect and select tone */
2896 new_state(EPOINT_STATE_OUT_DISCONNECT);
2897 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2898 /* if own_cause, we must release the join */
2899 if (e_ext.own_cause /* own cause */
2900 || !e_join_pattern) { /* no patterns */
2901 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have own cause or we have no patterns. (own_cause=%d pattern=%d)\n", ea_endpoint->ep_serial, e_ext.own_cause, e_join_pattern);
2902 if (message_type != MESSAGE_RELEASE)
2903 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2905 } else { /* else we enable audio */
2906 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2907 message->param.audiopath = 1;
2908 message_put(message);
2910 /* send disconnect message */
2911 SCPY(e_tone, cause);
2912 portlist = ea_endpoint->ep_portlist;
2914 set_tone(portlist, cause);
2915 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2916 portlist = portlist->next;
2920 /* join MESSAGE_SETUP */
2921 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2923 struct lcr_msg *message;
2924 // struct interface *interface;
2926 /* if we already in setup state, we just update the dialing with new digits */
2927 if (e_state == EPOINT_STATE_OUT_SETUP
2928 || e_state == EPOINT_STATE_OUT_OVERLAP) {
2929 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
2930 /* if digits changed, what we have already dialed */
2931 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
2932 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have dialed digits which have been changed or we have a new multidial, so we must redial.\n", ea_endpoint->ep_serial);
2933 /* release all ports */
2934 while((portlist = ea_endpoint->ep_portlist)) {
2935 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2936 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2937 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2938 message_put(message);
2939 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2940 ea_endpoint->free_portlist(portlist);
2943 /* disconnect audio */
2944 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2945 message->param.audiopath = 0;
2946 message_put(message);
2948 /* get dialing info */
2949 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
2950 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2951 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
2952 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
2953 new_state(EPOINT_STATE_OUT_OVERLAP);
2956 schedule_timer(&e_redial_timeout, 1, 0);
2959 /* if we have a pending redial, so we just adjust the dialing number */
2960 if (e_redial_timeout.active) {
2961 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) redial in progress, so we update the dialing number to %s.\n", ea_endpoint->ep_serial, param->setup.dialinginfo.id);
2962 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2965 if (!ea_endpoint->ep_portlist) {
2966 PERROR("ERROR: overlap dialing to a NULL port relation\n");
2968 if (ea_endpoint->ep_portlist->next) {
2969 PERROR("ERROR: overlap dialing to a port_list port relation\n");
2971 if (e_state == EPOINT_STATE_OUT_SETUP) {
2973 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) digits '%s' are queued because we didn't receive a setup acknowledge.\n", ea_endpoint->ep_serial, param->setup.dialinginfo.id);
2974 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2977 /* get what we have not dialed yet */
2978 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have already dialed '%s', we received '%s', what's left '%s'.\n", ea_endpoint->ep_serial, e_dialinginfo.id, param->setup.dialinginfo.id, param->setup.dialinginfo.id+strlen(e_dialinginfo.id));
2979 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2980 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2981 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
2982 message_put(message);
2983 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2985 /* always store what we have dialed or queued */
2986 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2990 if (e_state != EPOINT_STATE_IDLE) {
2991 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2994 /* if an internal extension is dialed, copy that number */
2995 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
2996 SCPY(e_ext.number, param->setup.dialinginfo.id);
2997 /* if an internal extension is dialed, get extension's info about caller */
2998 if (e_ext.number[0]) {
2999 if (!read_extension(&e_ext, e_ext.number)) {
3000 e_ext.number[0] = '\0';
3001 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3005 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3006 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3007 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3008 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3009 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3011 /* process (voice over) data calls */
3012 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3013 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3014 memset(&e_capainfo, 0, sizeof(e_capainfo));
3015 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3016 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3017 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3020 new_state(EPOINT_STATE_OUT_SETUP);
3021 /* call special setup routine */
3025 /* join MESSAGE_mISDNSIGNAL */
3026 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3028 struct lcr_msg *message;
3031 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3032 memcpy(&message->param, param, sizeof(union parameter));
3033 message_put(message);
3034 portlist = portlist->next;
3038 /* join MESSAGE_BRIDE */
3039 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3041 struct lcr_msg *message;
3044 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3045 memcpy(&message->param, param, sizeof(union parameter));
3046 message_put(message);
3047 portlist = portlist->next;
3051 /* join MESSAGE_NOTIFY */
3052 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3054 struct lcr_msg *message;
3057 if (param->notifyinfo.notify) {
3058 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3059 // /* if notification was generated locally, we turn hold music on/off */
3060 // if (param->notifyinfo.local)
3061 // NOTE: we always assume that we send hold music on suspension of call, because we don't track if audio is available or not (we assume that we always have no audio, to make it easier)
3065 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3066 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3068 set_tone(portlist, "");
3069 portlist = portlist->next;
3072 portlist = ea_endpoint->ep_portlist;
3077 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3079 set_tone(portlist, "hold");
3080 portlist = portlist->next;
3082 portlist = ea_endpoint->ep_portlist;
3087 /* save new state */
3088 e_tx_state = new_state;
3091 /* notify port(s) about it */
3093 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3094 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3095 /* handle restricted caller ids */
3096 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3097 /* display callerid if desired for extension */
3098 SCPY(message->param.notifyinfo.display, apply_callerid_display(message->param.notifyinfo.id, message->param.notifyinfo.itype, message->param.notifyinfo.ntype, message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL));
3099 message_put(message);
3100 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3101 portlist = portlist->next;
3105 /* join MESSAGE_DTMF */
3106 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3108 struct lcr_msg *message;
3111 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3112 memcpy(&message->param, param, sizeof(union parameter));
3113 message_put(message);
3114 portlist = portlist->next;
3118 /* JOIN sends messages to the endpoint
3120 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3122 struct port_list *portlist;
3123 struct lcr_msg *message;
3126 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3130 portlist = ea_endpoint->ep_portlist;
3132 // PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received message %d for active JOIN (terminal %s, caller id %s state=%d)\n", ea_endpoint->ep_serial, message, e_ext.number, e_callerinfo.id, e_state);
3133 switch(message_type) {
3134 /* JOIN SENDS TONE message */
3136 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received tone message: '%d'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->tone.name);
3137 set_tone(portlist, param->tone.name);
3140 /* JOIN SENDS CRYPT message */
3142 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received crypt message: '%d'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->crypt.type);
3143 join_crypt(portlist, message_type, param);
3146 /* JOIN sends INFORMATION message */
3147 case MESSAGE_INFORMATION:
3148 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received more digits: '%s'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->information.id);
3149 join_information(portlist, message_type, param);
3152 /* JOIN sends FACILITY message */
3153 case MESSAGE_FACILITY:
3154 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received facility\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3155 join_facility(portlist, message_type, param);
3158 /* JOIN sends OVERLAP message */
3159 case MESSAGE_OVERLAP:
3160 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received 'more info required'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3161 if (e_state!=EPOINT_STATE_IN_SETUP
3162 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3163 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3166 join_overlap(portlist, message_type, param);
3169 /* JOIN sends PROCEEDING message */
3170 case MESSAGE_PROCEEDING:
3171 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s (caller id '%s') received proceeding\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3172 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3173 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3176 join_proceeding(portlist, message_type, param);
3179 /* JOIN sends ALERTING message */
3180 case MESSAGE_ALERTING:
3181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received alerting\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3182 if (e_state!=EPOINT_STATE_IN_OVERLAP
3183 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3184 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3187 join_alerting(portlist, message_type, param);
3190 /* JOIN sends CONNECT message */
3191 case MESSAGE_CONNECT:
3192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received connect\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3193 if (e_state!=EPOINT_STATE_IN_OVERLAP
3194 && e_state!=EPOINT_STATE_IN_PROCEEDING
3195 && e_state!=EPOINT_STATE_IN_ALERTING) {
3196 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3199 join_connect(portlist, message_type, param);
3202 /* JOIN sends DISCONNECT/RELEASE message */
3203 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3204 case MESSAGE_RELEASE: /* JOIN releases */
3205 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received %s with cause %d location %d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, (message_type==MESSAGE_DISCONNECT)?"disconnect":"release", param->disconnectinfo.cause, param->disconnectinfo.location);
3206 join_disconnect_release(message_type, param);
3209 /* JOIN sends SETUP message */
3211 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint received setup from terminal='%s',id='%s' to id='%s' (dialing itype=%d)\n", ea_endpoint->ep_serial, param->setup.callerinfo.extension, param->setup.callerinfo.id, param->setup.dialinginfo.id, param->setup.dialinginfo.itype);
3212 join_setup(portlist, message_type, param);
3215 /* JOIN sends special mISDNSIGNAL message */
3216 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3217 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received mISDNsignal message.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3218 join_mISDNsignal(portlist, message_type, param);
3221 /* JOIN sends bridge message */
3222 case MESSAGE_BRIDGE: /* bride message to port */
3223 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bridge message.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3224 join_bridge(portlist, message_type, param);
3227 /* JOIN has pattern available */
3228 case MESSAGE_PATTERN: /* indicating pattern available */
3229 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received pattern availability.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3230 if (!e_join_pattern) {
3231 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3235 set_tone(portlist, NULL);
3236 portlist = portlist->next;
3238 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3239 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3240 message->param.audiopath = 1;
3241 message_put(message);
3245 /* JOIN has no pattern available */
3246 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3247 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received pattern NOT available.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3248 if (e_join_pattern) {
3249 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3251 /* disconnect our audio tx and rx */
3252 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3253 message->param.audiopath = 0;
3254 message_put(message);
3259 /* JOIN (dunno at the moment) */
3260 case MESSAGE_REMOTE_AUDIO:
3261 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received audio remote request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3262 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3263 message->param.audiopath = param->channel;
3264 message_put(message);
3268 /* JOIN sends a notify message */
3269 case MESSAGE_NOTIFY:
3270 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received notify.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3271 join_notify(portlist, message_type, param);
3274 /* JOIN wants keypad / dtmf */
3275 case MESSAGE_ENABLEKEYPAD:
3276 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received keypad enable request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3279 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3283 /* JOIN sends a DTMF message */
3285 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received dtmf.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3286 join_dtmf(portlist, message_type, param);
3290 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: #%d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
3295 /* pick_join will connect the first incoming call found. the endpoint
3296 * will receivce a MESSAGE_CONNECT.
3298 int match_list(char *list, char *item)
3300 char *end, *next = NULL;
3302 /* no list make matching */
3307 /* eliminate white spaces */
3308 while (*list > '\0' && *list <= ' ')
3314 /* if end of list is reached, we return */
3315 if (list[0] == '\0')
3317 /* if we have more than one entry (left) */
3318 if ((end = strchr(list, ',')))
3321 next = end = strchr(list, '\0');
3322 while (*(end-1) <= ' ')
3324 /* if string part matches item */
3325 if (!strncmp(list, item, end-list))
3331 void EndpointAppPBX::pick_join(char *extensions)
3333 struct lcr_msg *message;
3334 struct port_list *portlist;
3336 class EndpointAppPBX *eapp, *found;
3338 class JoinPBX *joinpbx;
3339 struct join_relation *relation;
3342 /* find an endpoint that is ringing internally or vbox with higher priority */
3345 eapp = apppbx_first;
3347 if (eapp!=this && ea_endpoint->ep_portlist) {
3348 portlist = eapp->ea_endpoint->ep_portlist;
3350 if ((port = find_port_id(portlist->port_id))) {
3351 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3352 if (match_list(extensions, eapp->e_ext.number)) {
3358 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3359 && port->p_state==PORT_STATE_OUT_ALERTING)
3360 if (match_list(extensions, eapp->e_ext.number)) {
3364 portlist = portlist->next;
3372 /* if no endpoint found */
3374 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) nobody is ringing internally (or we don't have her in the access list), so we disconnect.\n", ea_endpoint->ep_serial);
3376 set_tone(ea_endpoint->ep_portlist, "cause_10");
3377 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3378 new_state(EPOINT_STATE_OUT_DISCONNECT);
3383 if (ea_endpoint->ep_join_id) {
3384 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3387 if (!eapp->ea_endpoint->ep_join_id) {
3388 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3391 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3393 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3396 if (join->j_type != JOIN_TYPE_PBX) {
3397 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3400 joinpbx = (class JoinPBX *)join;
3401 relation = joinpbx->j_relation;
3403 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3406 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3407 relation = relation->next;
3409 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3414 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3416 if (options.deb & DEBUG_EPOINT) {
3417 class Join *debug_c = join_first;
3418 class Endpoint *debug_e = epoint_first;
3419 class Port *debug_p = port_first;
3421 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3423 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3425 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3426 debug_c = debug_c->next;
3428 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3430 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3431 debug_e = debug_e->next;
3433 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3435 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3436 debug_p = debug_p->next;
3441 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3442 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3443 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3445 /* connnecting our endpoint */
3446 new_state(EPOINT_STATE_CONNECT);
3447 if (e_ext.number[0])
3449 set_tone(ea_endpoint->ep_portlist, NULL);
3451 /* now we send a release to the ringing endpoint */
3452 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3453 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3454 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3455 message_put(message);
3457 /* we send a connect to the join with our caller id */
3458 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3459 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3460 message->param.connectinfo.present = e_callerinfo.present;
3461 message->param.connectinfo.screen = e_callerinfo.screen;
3462 message->param.connectinfo.itype = e_callerinfo.itype;
3463 message->param.connectinfo.ntype = e_callerinfo.ntype;
3464 message_put(message);
3466 /* we send a connect to our port with the remote callerid */
3467 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3468 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3469 message->param.connectinfo.present = eapp->e_callerinfo.present;
3470 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3471 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3472 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3473 /* handle restricted caller ids */
3474 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);
3475 /* display callerid if desired for extension */
3476 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));
3477 message_put(message);
3479 /* we send a connect to the audio path (not for vbox) */
3480 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3481 message->param.audiopath = 1;
3482 message_put(message);
3484 /* beeing paranoid, we make call update */
3485 trigger_work(&joinpbx->j_updatebridge);
3487 if (options.deb & DEBUG_EPOINT) {
3488 class Join *debug_c = join_first;
3489 class Endpoint *debug_e = epoint_first;
3490 class Port *debug_p = port_first;
3492 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3494 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3496 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3497 debug_c = debug_c->next;
3499 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3501 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3502 debug_e = debug_e->next;
3504 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3506 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3507 debug_p = debug_p->next;
3513 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3515 void EndpointAppPBX::join_join(void)
3518 struct lcr_msg *message;
3519 struct join_relation *our_relation, *other_relation;
3520 struct join_relation **our_relation_pointer, **other_relation_pointer;
3521 class Join *our_join, *other_join;
3522 class JoinPBX *our_joinpbx, *other_joinpbx;
3523 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3524 class Port *our_port, *other_port;
3525 class Pdss1 *our_pdss1, *other_pdss1;
3527 /* are we a candidate to join a join? */
3528 our_join = find_join_id(ea_endpoint->ep_join_id);
3530 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3533 if (our_join->j_type != JOIN_TYPE_PBX) {
3534 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3537 our_joinpbx = (class JoinPBX *)our_join;
3538 if (!ea_endpoint->ep_portlist) {
3539 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3542 if (!e_ext.number[0]) {
3543 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3546 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3548 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3551 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3552 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3555 our_pdss1 = (class Pdss1 *)our_port;
3557 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3558 other_eapp = apppbx_first;
3560 if (other_eapp == this) {
3561 other_eapp = other_eapp->next;
3564 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint candiate: (ep%d) terminal='%s' port=%s join=%d.\n", ea_endpoint->ep_serial, other_eapp->ea_endpoint->ep_serial, other_eapp->e_ext.number, (other_eapp->ea_endpoint->ep_portlist)?"YES":"NO", other_eapp->ea_endpoint->ep_join_id);
3565 if (other_eapp->e_ext.number[0] /* has terminal */
3566 && other_eapp->ea_endpoint->ep_portlist /* has port */
3567 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3568 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3569 if (other_port) { /* port still exists */
3570 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3571 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3572 other_pdss1 = (class Pdss1 *)other_port;
3573 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_m_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
3574 if (other_pdss1->p_m_hold /* port is on hold */
3575 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3576 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3579 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3582 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3585 other_eapp = other_eapp->next;
3588 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3591 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3593 /* if we have the same join */
3594 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3595 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3598 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3600 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3603 if (other_join->j_type != JOIN_TYPE_PBX) {
3604 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3607 other_joinpbx = (class JoinPBX *)other_join;
3608 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3609 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3613 /* remove relation to endpoint for join on hold */
3614 other_relation = other_joinpbx->j_relation;
3615 other_relation_pointer = &other_joinpbx->j_relation;
3616 while(other_relation) {
3617 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3618 /* detach other endpoint on hold */
3619 *other_relation_pointer = other_relation->next;
3620 FREE(other_relation, sizeof(struct join_relation));
3622 other_relation = *other_relation_pointer;
3623 other_eapp->ea_endpoint->ep_join_id = 0;
3627 /* change join/hold pointer of endpoint to the new join */
3628 temp_epoint = find_epoint_id(other_relation->epoint_id);
3630 if (temp_epoint->ep_join_id == other_join->j_serial)
3631 temp_epoint->ep_join_id = our_join->j_serial;
3634 other_relation_pointer = &other_relation->next;
3635 other_relation = other_relation->next;
3637 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3639 /* join call relations */
3640 our_relation = our_joinpbx->j_relation;
3641 our_relation_pointer = &our_joinpbx->j_relation;
3642 while(our_relation) {
3643 our_relation_pointer = &our_relation->next;
3644 our_relation = our_relation->next;
3646 *our_relation_pointer = other_joinpbx->j_relation;
3647 other_joinpbx->j_relation = NULL;
3648 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3650 /* release endpoint on hold */
3651 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3652 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3653 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3654 message_put(message);
3656 /* if we are not a partyline, we get partyline state from other join */
3657 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3659 /* remove empty join */
3661 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3663 /* mixer must update */
3664 trigger_work(&our_joinpbx->j_updatebridge);
3666 /* we send a retrieve to that endpoint */
3667 // mixer will update the hold-state of the join and send it to the endpoints is changes
3669 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3674 /* check if we have an external call
3675 * this is used to check for encryption ability
3677 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3679 struct join_relation *relation;
3681 class JoinPBX *joinpbx;
3682 class Endpoint *epoint;
3684 /* some paranoia check */
3685 if (!ea_endpoint->ep_portlist) {
3686 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3687 *errstr = "No Call";
3690 if (!e_ext.number[0]) {
3691 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3692 *errstr = "No Call";
3696 /* check if we have a join with 2 parties */
3697 join = find_join_id(ea_endpoint->ep_join_id);
3699 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3700 *errstr = "No Call";
3703 if (join->j_type != JOIN_TYPE_PBX) {
3704 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3705 *errstr = "No PBX Call";
3708 joinpbx = (class JoinPBX *)join;
3709 relation = joinpbx->j_relation;
3711 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3712 *errstr = "No Call";
3715 if (!relation->next) {
3716 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3717 *errstr = "No Call";
3720 if (relation->next->next) {
3721 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3722 *errstr = "Err: Conference";
3725 if (relation->epoint_id == ea_endpoint->ep_serial) {
3726 relation = relation->next;
3727 if (relation->epoint_id == ea_endpoint->ep_serial) {
3728 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3729 *errstr = "Software Error";
3734 /* check remote port for external call */
3735 epoint = find_epoint_id(relation->epoint_id);
3737 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3738 *errstr = "No Call";
3741 if (!epoint->ep_portlist) {
3742 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3743 *errstr = "No Call";
3746 *port = find_port_id(epoint->ep_portlist->port_id);
3748 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3749 *errstr = "No Call";
3752 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
3753 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3754 *errstr = "No Ext Call";
3757 if ((*port)->p_state != PORT_STATE_CONNECT) {
3758 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3759 *errstr = "No Ext Connect";
3765 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3767 const char *logtext = "unknown";
3770 switch(message_type) {
3772 trace_header("SETUP", dir);
3773 if (dir == DIRECTION_OUT)
3774 add_trace("to", NULL, "CH(%lu)", port_id);
3775 if (dir == DIRECTION_IN)
3776 add_trace("from", NULL, "CH(%lu)", port_id);
3777 if (param->setup.callerinfo.extension[0])
3778 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3779 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3780 switch(param->setup.callerinfo.present) {
3781 case INFO_PRESENT_RESTRICTED:
3782 add_trace("caller id", "present", "restricted");
3784 case INFO_PRESENT_ALLOWED:
3785 add_trace("caller id", "present", "allowed");
3788 add_trace("caller id", "present", "not available");
3790 if (param->setup.callerinfo.ntype2) {
3791 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3792 switch(param->setup.callerinfo.present) {
3793 case INFO_PRESENT_RESTRICTED:
3794 add_trace("caller id2", "present", "restricted");
3796 case INFO_PRESENT_ALLOWED:
3797 add_trace("caller id2", "present", "allowed");
3800 add_trace("caller id2", "present", "not available");
3803 if (param->setup.redirinfo.id[0]) {
3804 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3805 switch(param->setup.redirinfo.present) {
3806 case INFO_PRESENT_RESTRICTED:
3807 add_trace("redir'ing", "present", "restricted");
3809 case INFO_PRESENT_ALLOWED:
3810 add_trace("redir'ing", "present", "allowed");
3813 add_trace("redir'ing", "present", "not available");
3816 if (param->setup.dialinginfo.id[0])
3817 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3818 if (param->setup.dialinginfo.keypad[0])
3819 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3820 if (param->setup.dialinginfo.display[0])
3821 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3822 if (param->setup.dialinginfo.sending_complete)
3823 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3827 case MESSAGE_OVERLAP:
3828 trace_header("SETUP ACKNOWLEDGE", dir);
3829 if (dir == DIRECTION_OUT)
3830 add_trace("to", NULL, "CH(%lu)", port_id);
3831 if (dir == DIRECTION_IN)
3832 add_trace("from", NULL, "CH(%lu)", port_id);
3836 case MESSAGE_PROCEEDING:
3837 trace_header("PROCEEDING", dir);
3838 if (dir == DIRECTION_OUT)
3839 add_trace("to", NULL, "CH(%lu)", port_id);
3840 if (dir == DIRECTION_IN)
3841 add_trace("from", NULL, "CH(%lu)", port_id);
3845 case MESSAGE_ALERTING:
3846 trace_header("ALERTING", dir);
3847 if (dir == DIRECTION_OUT)
3848 add_trace("to", NULL, "CH(%lu)", port_id);
3849 if (dir == DIRECTION_IN)
3850 add_trace("from", NULL, "CH(%lu)", port_id);
3854 case MESSAGE_CONNECT:
3855 trace_header("CONNECT", dir);
3856 if (dir == DIRECTION_OUT)
3857 add_trace("to", NULL, "CH(%lu)", port_id);
3858 if (dir == DIRECTION_IN)
3859 add_trace("from", NULL, "CH(%lu)", port_id);
3860 if (param->connectinfo.extension[0])
3861 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3862 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3863 switch(param->connectinfo.present) {
3864 case INFO_PRESENT_RESTRICTED:
3865 add_trace("connect id", "present", "restricted");
3867 case INFO_PRESENT_ALLOWED:
3868 add_trace("connect id", "present", "allowed");
3871 add_trace("connect id", "present", "not available");
3873 if (param->connectinfo.display[0])
3874 add_trace("display", NULL, "%s", param->connectinfo.display);
3878 case MESSAGE_DISCONNECT:
3879 case MESSAGE_RELEASE:
3880 if (message_type == MESSAGE_DISCONNECT)
3881 trace_header("DISCONNECT", dir);
3883 trace_header("RELEASE", dir);
3884 if (dir == DIRECTION_OUT)
3885 add_trace("to", NULL, "CH(%lu)", port_id);
3886 if (dir == DIRECTION_IN)
3887 add_trace("from", NULL, "CH(%lu)", port_id);
3888 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3889 switch(param->disconnectinfo.location) {
3891 add_trace("cause", "location", "0-User");
3893 case LOCATION_PRIVATE_LOCAL:
3894 add_trace("cause", "location", "1-Local-PBX");
3896 case LOCATION_PUBLIC_LOCAL:
3897 add_trace("cause", "location", "2-Local-Exchange");
3899 case LOCATION_TRANSIT:
3900 add_trace("cause", "location", "3-Transit");
3902 case LOCATION_PUBLIC_REMOTE:
3903 add_trace("cause", "location", "4-Remote-Exchange");
3905 case LOCATION_PRIVATE_REMOTE:
3906 add_trace("cause", "location", "5-Remote-PBX");
3908 case LOCATION_INTERNATIONAL:
3909 add_trace("cause", "location", "7-International-Exchange");
3911 case LOCATION_BEYOND:
3912 add_trace("cause", "location", "10-Beyond-Interworking");
3915 add_trace("cause", "location", "%d", param->disconnectinfo.location);
3917 if (param->disconnectinfo.display[0])
3918 add_trace("display", NULL, "%s", param->disconnectinfo.display);
3922 case MESSAGE_NOTIFY:
3923 switch(param->notifyinfo.notify) {
3928 logtext = "USER_SUSPENDED";
3931 logtext = "BEARER_SERVICE_CHANGED";
3934 logtext = "USER_RESUMED";
3937 logtext = "CONFERENCE_ESTABLISHED";
3940 logtext = "CONFERENCE_DISCONNECTED";
3943 logtext = "OTHER_PARTY_ADDED";
3946 logtext = "ISOLATED";
3949 logtext = "REATTACHED";
3952 logtext = "OTHER_PARTY_ISOLATED";
3955 logtext = "OTHER_PARTY_REATTACHED";
3958 logtext = "OTHER_PARTY_SPLIT";
3961 logtext = "OTHER_PARTY_DISCONNECTED";
3964 logtext = "CONFERENCE_FLOATING";
3967 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
3970 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
3973 logtext = "CALL_IS_A_WAITING_CALL";
3976 logtext = "DIVERSION_ACTIVATED";
3979 logtext = "RESERVED_CT_1";
3982 logtext = "RESERVED_CT_2";
3985 logtext = "REVERSE_CHARGING";
3988 logtext = "REMOTE_HOLD";
3991 logtext = "REMOTE_RETRIEVAL";
3994 logtext = "CALL_IS_DIVERTING";
3997 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4001 trace_header("NOTIFY", dir);
4002 if (dir == DIRECTION_OUT)
4003 add_trace("to", NULL, "CH(%lu)", port_id);
4004 if (dir == DIRECTION_IN)
4005 add_trace("from", NULL, "CH(%lu)", port_id);
4006 if (param->notifyinfo.notify)
4007 add_trace("indicator", NULL, "%s", logtext);
4008 if (param->notifyinfo.id[0]) {
4009 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4010 switch(param->notifyinfo.present) {
4011 case INFO_PRESENT_RESTRICTED:
4012 add_trace("redir'on", "present", "restricted");
4014 case INFO_PRESENT_ALLOWED:
4015 add_trace("redir'on", "present", "allowed");
4018 add_trace("redir'on", "present", "not available");
4021 if (param->notifyinfo.display[0])
4022 add_trace("display", NULL, "%s", param->notifyinfo.display);
4026 case MESSAGE_PROGRESS:
4027 switch(param->progressinfo.progress) {
4029 logtext = "Call is not end to end ISDN";
4032 logtext = "Destination address is non-ISDN";
4035 logtext = "Origination address is non-ISDN";
4038 logtext = "Call has returned to the ISDN";
4041 logtext = "In-band info or pattern available";
4044 SPRINT(buffer, "%d", param->progressinfo.progress);
4048 trace_header("PROGRESS", dir);
4049 if (dir == DIRECTION_OUT)
4050 add_trace("to", NULL, "CH(%lu)", port_id);
4051 if (dir == DIRECTION_IN)
4052 add_trace("from", NULL, "CH(%lu)", port_id);
4053 add_trace("indicator", NULL, "%s", logtext);
4054 switch(param->progressinfo.location) {
4056 add_trace("cause", "location", "0-User");
4058 case LOCATION_PRIVATE_LOCAL:
4059 add_trace("cause", "location", "1-Local-PBX");
4061 case LOCATION_PUBLIC_LOCAL:
4062 add_trace("cause", "location", "2-Local-Exchange");
4064 case LOCATION_TRANSIT:
4065 add_trace("cause", "location", "3-Transit");
4067 case LOCATION_PUBLIC_REMOTE:
4068 add_trace("cause", "location", "4-Remote-Exchange");
4070 case LOCATION_PRIVATE_REMOTE:
4071 add_trace("cause", "location", "5-Remote-PBX");
4073 case LOCATION_INTERNATIONAL:
4074 add_trace("cause", "location", "7-International-Exchange");
4076 case LOCATION_BEYOND:
4077 add_trace("cause", "location", "10-Beyond-Interworking");
4080 add_trace("cause", "location", "%d", param->progressinfo.location);
4085 case MESSAGE_INFORMATION:
4086 trace_header("INFORMATION", dir);
4087 if (dir == DIRECTION_OUT)
4088 add_trace("to", NULL, "CH(%lu)", port_id);
4089 if (dir == DIRECTION_IN)
4090 add_trace("from", NULL, "CH(%lu)", port_id);
4091 if (param->information.id[0])
4092 add_trace("dialing", NULL, "%s", param->information.id);
4093 if (param->information.display[0])
4094 add_trace("display", NULL, "%s", param->information.display);
4095 if (param->information.sending_complete)
4096 add_trace("complete", NULL, "true", param->information.sending_complete);
4100 case MESSAGE_FACILITY:
4101 trace_header("FACILITY", dir);
4102 if (dir == DIRECTION_OUT)
4103 add_trace("to", NULL, "CH(%lu)", port_id);
4104 if (dir == DIRECTION_IN)
4105 add_trace("from", NULL, "CH(%lu)", port_id);
4110 trace_header("TONE", dir);
4111 if (dir == DIRECTION_OUT)
4112 add_trace("to", NULL, "CH(%lu)", port_id);
4113 if (dir == DIRECTION_IN)
4114 add_trace("from", NULL, "CH(%lu)", port_id);
4115 if (param->tone.name[0]) {
4116 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4117 add_trace("name", NULL, "%s", param->tone.name);
4119 add_trace("off", NULL, NULL);
4123 case MESSAGE_SUSPEND:
4124 case MESSAGE_RESUME:
4125 if (message_type == MESSAGE_SUSPEND)
4126 trace_header("SUSPEND", dir);
4128 trace_header("RESUME", dir);
4129 if (dir == DIRECTION_OUT)
4130 add_trace("to", NULL, "CH(%lu)", port_id);
4131 if (dir == DIRECTION_IN)
4132 add_trace("from", NULL, "CH(%lu)", port_id);
4133 if (param->parkinfo.len)
4134 add_trace("length", NULL, "%d", param->parkinfo.len);
4139 case MESSAGE_BCHANNEL:
4140 trace_header("BCHANNEL", dir);
4141 switch(param->bchannel.type) {
4142 case BCHANNEL_REQUEST:
4143 add_trace("type", NULL, "request");
4145 case BCHANNEL_ASSIGN:
4146 add_trace("type", NULL, "assign");
4148 case BCHANNEL_ASSIGN_ACK:
4149 add_trace("type", NULL, "assign_ack");
4151 case BCHANNEL_REMOVE:
4152 add_trace("type", NULL, "remove");
4154 case BCHANNEL_REMOVE_ACK:
4155 add_trace("type", NULL, "remove_ack");
4158 if (param->bchannel.addr)
4159 add_trace("address", NULL, "%x", param->bchannel.addr);
4165 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4169 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4171 struct lcr_msg *message;
4175 if (!portlist->port_id)
4178 if (!e_connectedmode) {
4179 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4180 message->param.disconnectinfo.cause = cause;
4181 message->param.disconnectinfo.location = location;
4183 SCPY(message->param.disconnectinfo.display, display);
4185 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4187 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4189 SCPY(message->param.notifyinfo.display, display);
4191 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4193 message_put(message);
4194 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);