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)],
615 struct port_settings port_settings;
618 struct admin_list *admin;
621 int mode = B_MODE_TRANSPARENT;
623 /* set bchannel mode */
624 mode = e_capainfo.source_mode;
626 /* create settings for creating port */
627 memset(&port_settings, 0, sizeof(port_settings));
629 SCPY(port_settings.tones_dir, e_ext.tones_dir);
631 SCPY(port_settings.tones_dir, options.tones_dir);
632 port_settings.no_seconds = e_ext.no_seconds;
634 /* 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 */
636 /* check what dialinginfo.itype we got */
637 switch(e_dialinginfo.itype) {
638 /* *********************** call to extension or vbox */
639 case INFO_ITYPE_ISDN_EXTENSION:
640 /* check if we deny incoming calls when we use an extension */
641 if (e_ext.noknocking) {
642 atemp = apppbx_first;
645 if (!strcmp(atemp->e_ext.number, e_ext.number))
650 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
651 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
652 return; /* must exit here */
655 /* FALL THROUGH !!!! */
656 case INFO_ITYPE_VBOX:
657 /* get dialed extension's info */
658 // SCPY(exten, e_dialinginfo.id);
659 // if (strchr(exten, ','))
660 // *strchr(exten, ',') = '\0';
661 // if (!read_extension(&e_ext, exten))
662 if (!read_extension(&e_ext, e_dialinginfo.id)) {
663 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
664 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
665 return; /* must exit here */
667 e_dialinginfo.sending_complete = 1;
669 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
670 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
675 /* string from unconditional call forward (cfu) */
678 /* present to forwarded party */
679 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
680 e_callerinfo.present = INFO_PRESENT_ALLOWED;
682 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
686 /* string from busy call forward (cfb) */
689 class EndpointAppPBX *checkapp = apppbx_first;
691 if (checkapp != this) { /* any other endpoint except our own */
692 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
693 /* present to forwarded party */
694 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
695 e_callerinfo.present = INFO_PRESENT_ALLOWED;
697 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
701 checkapp = checkapp->next;
705 /* string from no-response call forward (cfnr) */
708 /* when cfnr is done, out_setup() will setup the call */
710 /* present to forwarded party */
711 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
712 e_callerinfo.present = INFO_PRESENT_ALLOWED;
716 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
717 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
718 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
719 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);
723 /* call to all internal interfaces */
724 p = e_ext.interfaces;
725 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
729 while(*p!=',' && *p!='\0')
734 /* search interface */
735 interface = hunt_interface(ifname);
737 trace_header("INTERFACE (not found)", DIRECTION_NONE);
738 add_trace("interface", NULL, "%s", ifname);
742 /* found interface */
743 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
745 if (interface->gsm_bs) {
746 SPRINT(portname, "%s-%d-out", interface->name, 0);
747 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
748 earlyb = (interface->is_earlyb == IS_YES);
752 if (interface->gsm_ms) {
753 SPRINT(portname, "%s-%d-out", interface->name, 0);
754 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
755 earlyb = (interface->is_earlyb == IS_YES);
759 if (interface->sip) {
760 SPRINT(portname, "%s-%d-out", interface->name, 0);
761 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
762 earlyb = (interface->is_earlyb == IS_YES);
767 /* hunt for mISDNport and create Port */
768 mISDNport = hunt_port(ifname, &channel);
770 trace_header("INTERFACE (busy)", DIRECTION_NONE);
771 add_trace("interface", NULL, "%s", ifname);
776 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
779 port = ss5_hunt_line(mISDNport);
782 if (mISDNport->ifport->remote) {
785 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
790 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
791 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
795 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
797 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);
798 earlyb = mISDNport->earlyb;
800 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
801 add_trace("interface", NULL, "%s", ifname);
807 FATAL("Failed to create Port instance\n");
808 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
809 memset(&dialinginfo, 0, sizeof(dialinginfo));
810 SCPY(dialinginfo.id, e_dialinginfo.id);
811 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
812 dialinginfo.ntype = e_dialinginfo.ntype;
813 /* create port_list relation */
814 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
816 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
818 goto check_anycall_intern;
821 if (e_callerinfo.id[0] && e_ext.display_name) {
822 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
824 SCPY(e_callerinfo.name, dirname);
826 // dss1 = (class Pdss1 *)port;
828 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
829 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
830 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
831 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
832 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
833 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
834 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
835 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
836 //terminal if (e_dialinginfo.id)
837 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
838 /* handle restricted caller ids */
839 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);
840 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);
841 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);
842 /* display callerid if desired for extension */
843 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));
844 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
845 /* use cnip, if enabld */
846 // if (!e_ext.centrex)
847 // message->param.setup.callerinfo.name[0] = '\0';
848 /* screen clip if prefix is required */
849 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
850 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
851 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
852 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
854 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
855 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
856 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
857 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
859 /* use internal caller id */
860 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
861 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
862 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
863 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
865 message_put(message);
866 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
870 /* string from parallel call forward (cfp) */
873 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
874 e_callerinfo.present = INFO_PRESENT_ALLOWED;
875 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
879 vbox_only: /* entry point for answering machine only */
880 cfu_only: /* entry point for cfu */
881 cfb_only: /* entry point for cfb */
882 cfnr_only: /* entry point for cfnr */
883 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
887 /* only if vbox should be dialed, and terminal is given */
888 if (!strcmp(p, "vbox") && e_ext.number[0]) {
889 /* go to the end of p */
892 /* answering vbox call */
893 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
895 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
896 FATAL("No memory for VBOX Port instance\n");
897 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
898 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
901 while(*p!=',' && *p!='\0')
906 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
908 /* hunt for mISDNport and create Port */
909 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
911 /* creating EXTERNAL port*/
912 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
915 port = ss5_hunt_line(mISDNport);
918 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);
920 FATAL("No memory for Port instance\n");
921 earlyb = mISDNport->earlyb;
926 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
927 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
932 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
933 goto check_anycall_intern;
935 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
936 memset(&dialinginfo, 0, sizeof(dialinginfo));
937 SCPY(dialinginfo.id, cfp);
938 dialinginfo.itype = INFO_ITYPE_ISDN;
939 dialinginfo.ntype = e_dialinginfo.ntype;
940 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
942 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
944 goto check_anycall_intern;
946 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
947 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
948 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
949 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
950 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
951 /* if clip is hidden */
952 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
953 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
954 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
955 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
956 message->param.setup.callerinfo.present = e_ext.callerid_present;
957 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
959 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
960 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
961 //terminal if (e_dialinginfo.id)
962 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
963 /* handle restricted caller ids */
964 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);
965 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);
966 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);
967 /* display callerid if desired for extension */
968 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));
969 message_put(message);
970 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
974 check_anycall_intern:
975 /* now we have all ports created */
977 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
979 if (!ea_endpoint->ep_join_id)
981 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
982 return; /* must exit here */
986 /* *********************** external call */
988 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
989 /* call to extenal interfaces */
990 if (e_dialinginfo.keypad[0])
991 number_p = e_dialinginfo.keypad;
993 number_p = e_dialinginfo.id;
996 while(*number_p!=',' && *number_p!='\0')
997 SCCAT(number, *number_p++);
998 if (*number_p == ',')
1002 ifname_p = e_dialinginfo.interfaces;
1003 if (*ifname_p == '+')
1008 while(*ifname_p!=',' && *ifname_p!='\0')
1009 SCCAT(ifname, *ifname_p++);
1010 if (*ifname_p == ',')
1012 /* found interface name */
1014 /* search interface */
1015 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, ifname[0]?ifname:"any interface");
1016 interface = hunt_interface(ifname[0]?ifname:NULL);
1018 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1019 add_trace("interface", NULL, "%s", ifname);
1023 /* found interface */
1025 if (interface->gsm_bs) {
1026 SPRINT(portname, "%s-%d-out", interface->name, 0);
1027 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1028 earlyb = (interface->is_earlyb == IS_YES);
1032 if (interface->gsm_ms) {
1033 SPRINT(portname, "%s-%d-out", interface->name, 0);
1034 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1035 earlyb = (interface->is_earlyb == IS_YES);
1039 if (interface->sip) {
1040 SPRINT(portname, "%s-%d-out", interface->name, 0);
1041 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1042 earlyb = (interface->is_earlyb == IS_YES);
1047 /* hunt for mISDNport and create Port */
1048 mISDNport = hunt_port(ifname[0]?ifname:NULL, &channel);
1050 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1051 add_trace("interface", NULL, "%s", ifname[0]?ifname:"any interface");
1055 /* creating EXTERNAL port*/
1056 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1060 port = ss5_hunt_line(mISDNport);
1063 if (mISDNport->ifport->remote) {
1064 admin = admin_first;
1066 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1068 admin = admin->next;
1071 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1072 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1076 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1078 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);
1079 earlyb = mISDNport->earlyb;
1081 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
1082 add_trace("interface", NULL, "%s", ifname);
1088 FATAL("No memory for Port instance\n");
1089 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1090 memset(&dialinginfo, 0, sizeof(dialinginfo));
1091 if (e_dialinginfo.keypad[0])
1092 SCPY(dialinginfo.keypad, number);
1094 SCPY(dialinginfo.id, number);
1095 dialinginfo.itype = INFO_ITYPE_ISDN;
1096 dialinginfo.ntype = e_dialinginfo.ntype;
1097 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1098 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1100 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1104 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1105 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1106 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1107 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1108 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1109 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1110 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1111 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1112 //terminal if (e_dialinginfo.id)
1113 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1114 /* handle restricted caller ids */
1115 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);
1116 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);
1117 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);
1118 /* display callerid if desired for extension */
1119 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));
1120 message_put(message);
1121 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1124 /* found an interface
1125 * continue only if + is given, so every interface is calles parallel */
1126 if (e_dialinginfo.interfaces[0] != '+')
1128 } while (*ifname_p);
1131 /* now we have all ports created */
1133 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1135 if (!ea_endpoint->ep_join_id)
1137 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1138 return; /* must exit here */
1145 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1147 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1149 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1152 unsched_timer(&ea->e_redial_timeout);
1153 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1154 ea->e_multipoint_cause = 0;
1155 ea->e_multipoint_location = 0;
1156 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1157 ea->e_join_pattern = 0;
1158 ea->process_dialing(1);
1159 /* we must exit, because our endpoint might be gone */
1164 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1166 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1168 if (!ea->e_action) {
1169 unsched_timer(&ea->e_redial_timeout);
1170 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1171 ea->process_dialing(0);
1172 /* we must exit, because our endpoint might be gone */
1178 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1180 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1182 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1184 ea->new_state(EPOINT_STATE_OUT_SETUP);
1185 /* call special setup routine */
1191 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1193 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1195 /* leave power dialing on */
1196 ea->e_powerdial_on = 1;
1197 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1200 ea->e_ruleset = ruleset_main;
1202 ea->e_rule = ea->e_ruleset->rule_first;
1203 ea->e_action = NULL;
1204 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1205 ea->process_dialing(0);
1210 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1212 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1213 struct port_list *portlist;
1214 struct lcr_msg *message;
1216 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1218 /* release all ports */
1219 while((portlist = ea->ea_endpoint->ep_portlist)) {
1220 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1221 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1222 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1223 message_put(message);
1224 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1225 ea->ea_endpoint->free_portlist(portlist);
1228 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1229 message->param.audiopath = 0;
1230 message_put(message);
1231 /* indicate no patterns */
1232 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1233 message_put(message);
1234 /* set setup state, since we have no response from the new join */
1235 ea->new_state(EPOINT_STATE_OUT_SETUP);
1240 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1242 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1244 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);
1250 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1252 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1254 if (ea->e_state == EPOINT_STATE_IDLE) {
1255 /* epoint is idle, check callback */
1256 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1257 ea->new_state(EPOINT_STATE_OUT_SETUP);
1264 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1266 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1268 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1269 struct port_list *portlist;
1271 ea->e_ruleset = ruleset_main;
1273 ea->e_rule = ea->e_ruleset->rule_first;
1274 ea->e_action = NULL;
1275 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1276 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1278 ea->e_connectedmode = 0;
1280 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1281 portlist = ea->ea_endpoint->ep_portlist;
1283 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1284 ea->set_tone(portlist, "cause_10");
1291 /* doing a hookflash */
1292 void EndpointAppPBX::hookflash(void)
1297 /* be sure that we are active */
1299 e_tx_state = NOTIFY_STATE_ACTIVE;
1301 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1303 if (ea_endpoint->ep_use > 1) {
1304 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1307 /* dialtone after pressing the hash key */
1308 process_hangup(e_join_cause, e_join_location);
1309 e_multipoint_cause = 0;
1310 e_multipoint_location = 0;
1311 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1313 port->set_echotest(0);
1315 if (ea_endpoint->ep_join_id) {
1316 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1318 e_ruleset = ruleset_main;
1320 e_rule = e_ruleset->rule_first;
1322 new_state(EPOINT_STATE_IN_OVERLAP);
1323 e_connectedmode = 1;
1324 SCPY(e_dialinginfo.id, e_ext.prefix);
1325 e_extdialing = e_dialinginfo.id;
1327 if (e_dialinginfo.id[0]) {
1328 set_tone(ea_endpoint->ep_portlist, "dialing");
1331 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1339 /* messages from port
1341 /* port MESSAGE_SETUP */
1342 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1344 struct lcr_msg *message;
1346 int writeext; /* flags need to write extension after modification */
1349 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1351 portlist->port_type = param->setup.port_type;
1352 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1353 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1354 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1355 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1356 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
1358 /* convert (inter-)national number type */
1359 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1360 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1362 // e_dtmf = param->setup.dtmf;
1363 /* screen incoming caller id */
1364 if (e_callerinfo.interface[0]) {
1365 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface);
1366 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
1367 do_screen(0, e_redirinfo.id, sizeof(e_redirinfo.id), &e_redirinfo.ntype, &e_redirinfo.present, e_callerinfo.interface);
1370 /* process extension */
1371 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1372 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1373 /* port makes call from extension */
1374 SCPY(e_callerinfo.extension, e_callerinfo.id);
1375 SCPY(e_ext.number, e_callerinfo.extension);
1376 SCPY(e_extension_interface, e_callerinfo.interface);
1378 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1381 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1382 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1384 /* get extension's info about caller */
1385 if (!read_extension(&e_ext, e_ext.number)) {
1386 /* extension doesn't exist */
1387 trace_header("EXTENSION (not created)", DIRECTION_IN);
1388 add_trace("extension", NULL, "%s", e_ext.number);
1390 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1391 new_state(EPOINT_STATE_OUT_DISCONNECT);
1392 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1393 e_ext.number[0] = '\0'; /* no terminal */
1398 /* put prefix (next) in front of e_dialinginfo.id */
1399 if (e_ext.next[0]) {
1400 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1401 SCPY(e_dialinginfo.id, buffer);
1402 e_ext.next[0] = '\0';
1404 } else if (e_ext.prefix[0]) {
1405 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1406 SCPY(e_dialinginfo.id, buffer);
1409 /* screen caller id by extension's config */
1410 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1412 SCPY(e_callerinfo.name, e_ext.name);
1413 /* use caller id (or if exist: id_next_call) for this call */
1414 if (e_ext.id_next_call_present >= 0) {
1415 SCPY(e_callerinfo.id, e_ext.id_next_call);
1416 /* if we restrict the pesentation */
1417 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1418 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1419 else e_callerinfo.present = e_ext.id_next_call_present;
1420 e_callerinfo.ntype = e_ext.id_next_call_type;
1421 e_ext.id_next_call_present = -1;
1424 SCPY(e_callerinfo.id, e_ext.callerid);
1425 /* if we restrict the pesentation */
1426 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1427 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1428 else e_callerinfo.present = e_ext.callerid_present;
1429 e_callerinfo.ntype = e_ext.callerid_type;
1431 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1433 /* extension is written */
1435 write_extension(&e_ext, e_ext.number);
1437 /* set volume of rx and tx */
1438 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1439 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1440 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1441 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1442 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1443 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1444 message_put(message);
1447 /* start recording if enabled */
1448 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1449 /* check if we are a terminal */
1450 if (e_ext.number[0] == '\0')
1451 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1453 port = find_port_id(portlist->port_id);
1455 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1459 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1460 /* no terminal identification */
1461 e_ext.number[0] = '\0';
1462 e_extension_interface[0] = '\0';
1463 memset(&e_ext, 0, sizeof(e_ext));
1464 e_ext.rights = 4; /* right to dial internat */
1468 e_ruleset = ruleset_main;
1470 e_rule = e_ruleset->rule_first;
1472 e_extdialing = e_dialinginfo.id;
1473 new_state(EPOINT_STATE_IN_SETUP);
1474 if (e_dialinginfo.id[0]) {
1475 set_tone(portlist, "dialing");
1477 if (e_ext.number[0])
1478 set_tone(portlist, "dialpbx");
1480 set_tone(portlist, "dialtone");
1483 if (e_state == EPOINT_STATE_IN_SETUP) {
1484 /* request MORE info, if not already at higher state */
1485 new_state(EPOINT_STATE_IN_OVERLAP);
1486 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1487 message_put(message);
1488 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1492 /* port MESSAGE_INFORMATION */
1493 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1495 struct lcr_msg *message;
1497 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1499 /* ignore information message without digit information */
1500 if (!param->information.id[0])
1505 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1507 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1512 /* if vbox_play is done, the information are just used as they come */
1514 if (e_action->index == ACTION_VBOX_PLAY) {
1515 /* concat dialing string */
1516 SCAT(e_dialinginfo.id, param->information.id);
1521 /* keypad when disconnect but in connected mode */
1522 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1523 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1524 /* processing keypad function */
1525 if (param->information.id[0] == '0') {
1531 /* keypad when connected */
1532 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1533 if (e_enablekeypad) {
1534 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1535 memcpy(&message->param, param, sizeof(union parameter));
1536 message_put(message);
1540 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1541 /* processing keypad function */
1542 if (param->information.id[0] == '0') {
1545 if (param->information.id[0])
1546 keypad_function(param->information.id[0]);
1548 if (e_ext.number[0])
1549 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1551 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1556 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1557 if (e_ext.number[0])
1558 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1560 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1564 if (!param->information.id[0])
1566 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1567 set_tone(portlist, "dialing");
1570 if (e_action->index==ACTION_OUTDIAL
1571 || e_action->index==ACTION_EXTERNAL
1572 || e_action->index==ACTION_REMOTE) {
1574 set_tone(portlist, "dialing");
1575 else if (!e_extdialing[0])
1576 set_tone(portlist, "dialing");
1578 /* concat dialing string */
1579 SCAT(e_dialinginfo.id, param->information.id);
1583 /* port MESSAGE_DTMF */
1584 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1587 struct lcr_msg *message;
1591 /* only if dtmf detection is enabled */
1593 trace_header("DTMF (disabled)", DIRECTION_IN);
1597 trace_header("DTMF", DIRECTION_IN);
1598 add_trace("digit", NULL, "%c", param->dtmf);
1602 NOTE: vbox is now handled due to overlap state
1603 /* if vbox_play is done, the dtmf digits are just used as they come */
1605 if (e_action->index == ACTION_VBOX_PLAY) {
1606 /* concat dialing string */
1607 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1608 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1609 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1612 /* continue to process *X# sequences */
1616 /* check for *X# sequence */
1617 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1618 if (e_enablekeypad) {
1619 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1620 memcpy(&message->param, param, sizeof(union parameter));
1621 message_put(message);
1624 if (e_dtmf_time+3 < now) {
1625 /* the last digit was too far in the past to be a sequence */
1626 if (param->dtmf == '*')
1627 /* only start is allowed in the sequence */
1632 /* we have a sequence of digits, see what we got */
1633 if (param->dtmf == '*')
1635 else if (param->dtmf>='0' && param->dtmf<='9') {
1636 /* we need to have a star before we receive the digit of the sequence */
1637 if (e_dtmf_last == '*')
1638 e_dtmf_last = param->dtmf;
1639 } else if (param->dtmf == '#') {
1641 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1642 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1643 if (e_dtmf_last == '0') {
1647 /* processing keypad function */
1649 keypad_function(e_dtmf_last);
1655 /* set last time of dtmf */
1660 /* check for ## hookflash during dialing */
1662 if (e_action->index==ACTION_PASSWORD
1663 || e_action->index==ACTION_PASSWORD_WRITE)
1665 if (param->dtmf=='#') { /* current digit is '#' */
1666 if (e_state==EPOINT_STATE_IN_DISCONNECT
1667 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1681 /* dialing using dtmf digit */
1682 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1683 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1684 set_tone(portlist, "dialing");
1686 /* concat dialing string */
1687 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1688 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1689 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1695 /* port MESSAGE_CRYPT */
1696 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1699 /* send crypt response to cryptman */
1700 if (param->crypt.type == CR_MESSAGE_IND)
1701 cryptman_msg2man(param->crypt.data, param->crypt.len);
1703 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1707 /* port MESSAGE_OVERLAP */
1708 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1710 struct lcr_msg *message;
1712 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1714 /* signal to call tool */
1715 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1717 if (e_dialing_queue[0] && portlist) {
1718 /* send what we have not dialed yet, because we had no setup complete */
1719 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1720 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1721 SCPY(message->param.information.id, e_dialing_queue);
1722 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1723 message_put(message);
1724 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1725 e_dialing_queue[0] = '\0';
1727 /* check if pattern is available */
1728 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1729 /* indicate patterns */
1730 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1731 message_put(message);
1733 /* connect audio, if not already */
1734 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1735 message->param.audiopath = 1;
1736 message_put(message);
1738 /* indicate no patterns */
1739 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1740 message_put(message);
1742 /* disconnect audio, if not already */
1743 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1744 message->param.audiopath = 0;
1745 message_put(message);
1747 new_state(EPOINT_STATE_OUT_OVERLAP);
1748 /* if we are in a join */
1749 if (ea_endpoint->ep_join_id) {
1750 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1751 memcpy(&message->param, param, sizeof(union parameter));
1752 message_put(message);
1756 /* port MESSAGE_PROCEEDING */
1757 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1759 struct lcr_msg *message;
1761 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1763 /* signal to call tool */
1764 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1766 e_state = EPOINT_STATE_OUT_PROCEEDING;
1767 /* check if pattern is availatle */
1768 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1769 /* indicate patterns */
1770 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1771 message_put(message);
1773 /* connect audio, if not already */
1774 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1775 message->param.audiopath = 1;
1776 message_put(message);
1778 /* indicate no patterns */
1779 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1780 message_put(message);
1782 /* disconnect audio, if not already */
1783 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1784 message->param.audiopath = 0;
1785 message_put(message);
1787 /* if we are in a call */
1788 if (ea_endpoint->ep_join_id) {
1789 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1790 memcpy(&message->param, param, sizeof(union parameter));
1791 message_put(message);
1795 /* port MESSAGE_ALERTING */
1796 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1798 struct lcr_msg *message;
1800 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1802 /* signal to call tool */
1803 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1806 // set_tone(portlist, "hold");
1808 new_state(EPOINT_STATE_OUT_ALERTING);
1809 /* check if pattern is available */
1810 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1811 /* indicate patterns */
1812 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1813 message_put(message);
1815 /* connect audio, if not already */
1816 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1817 message->param.audiopath = 1;
1818 message_put(message);
1820 /* indicate no patterns */
1821 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1822 message_put(message);
1824 /* disconnect audio, if not already */
1825 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1826 message->param.audiopath = 0;
1827 message_put(message);
1829 /* if we are in a call */
1830 if (ea_endpoint->ep_join_id) {
1831 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1832 memcpy(&message->param, param, sizeof(union parameter));
1833 message_put(message);
1837 /* port MESSAGE_CONNECT */
1838 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1840 struct lcr_msg *message;
1842 unsigned int port_id = portlist->port_id;
1843 struct port_list *tportlist;
1847 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1849 /* signal to call tool */
1850 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1852 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1853 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1854 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1855 tportlist = ea_endpoint->ep_portlist;
1856 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1857 tportlist = tportlist->next;
1858 if (tportlist->port_id == port_id)
1859 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1860 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1861 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1862 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1863 message_put(message);
1864 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1865 ea_endpoint->free_portlist(tportlist);
1867 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1872 if (e_callerinfo.interface[0])
1873 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface);
1875 /* screen connected name */
1877 SCPY(e_connectinfo.name, e_ext.name);
1879 /* add internal id to colp */
1880 SCPY(e_connectinfo.extension, e_ext.number);
1882 /* we store the connected port number */
1883 SCPY(e_extension_interface, e_connectinfo.interface);
1885 /* for internal and am calls, we get the extension's id */
1886 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1887 SCPY(e_connectinfo.id, e_ext.callerid);
1888 SCPY(e_connectinfo.extension, e_ext.number);
1889 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1890 e_connectinfo.ntype = e_ext.callerid_type;
1891 e_connectinfo.present = e_ext.callerid_present;
1893 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
1894 e_connectinfo.itype = INFO_ITYPE_VBOX;
1895 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1898 new_state(EPOINT_STATE_CONNECT);
1900 /* set volume of rx and tx */
1901 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1902 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1903 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1904 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1905 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1906 message_put(message);
1909 unsched_timer(&e_cfnr_timeout);
1910 unsched_timer(&e_cfnr_call_timeout);
1911 if (e_ext.number[0])
1912 e_dtmf = 1; /* allow dtmf */
1915 /* other calls with no caller id (or not available for the extension) and force colp */
1916 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
1917 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
1918 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
1919 /* external extension answered */
1920 port = find_port_id(portlist->port_id);
1922 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
1923 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1928 /* send connect to join */
1929 if (ea_endpoint->ep_join_id) {
1930 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1931 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1932 message_put(message);
1934 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1935 message->param.audiopath = 1;
1936 message_put(message);
1937 } else if (!e_adminid) {
1939 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
1940 SCPY(e_ext.number, e_cbcaller);
1941 new_state(EPOINT_STATE_IN_OVERLAP);
1942 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1944 /* get extension's info about terminal */
1945 if (!read_extension(&e_ext, e_ext.number)) {
1946 /* extension doesn't exist */
1947 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1948 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1949 new_state(EPOINT_STATE_OUT_DISCONNECT);
1950 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1954 /* put prefix in front of e_cbdialing */
1955 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
1956 SCPY(e_dialinginfo.id, buffer);
1957 e_dialinginfo.itype = INFO_ITYPE_ISDN;
1958 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1960 /* use caller id (or if exist: id_next_call) for this call */
1961 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1962 SCPY(e_callerinfo.extension, e_ext.number);
1963 if (e_ext.id_next_call_present >= 0) {
1964 SCPY(e_callerinfo.id, e_ext.id_next_call);
1965 e_callerinfo.present = e_ext.id_next_call_present;
1966 e_callerinfo.ntype = e_ext.id_next_call_type;
1967 e_ext.id_next_call_present = -1;
1968 /* extension is written */
1969 write_extension(&e_ext, e_ext.number);
1971 SCPY(e_callerinfo.id, e_ext.callerid);
1972 e_callerinfo.present = e_ext.callerid_present;
1973 e_callerinfo.ntype = e_ext.callerid_type;
1975 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1977 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
1980 /* check if caller id is NOT authenticated */
1981 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
1982 /* make call state to enter password */
1983 new_state(EPOINT_STATE_IN_OVERLAP);
1984 e_action = &action_password_write;
1985 unsched_timer(&e_match_timeout);
1986 e_match_to_action = NULL;
1987 e_dialinginfo.id[0] = '\0';
1988 e_extdialing = strchr(e_dialinginfo.id, '\0');
1989 schedule_timer(&e_password_timeout, 20, 0);
1992 /* incoming call (callback) */
1993 e_ruleset = ruleset_main;
1995 e_rule = e_ruleset->rule_first;
1997 e_extdialing = e_dialinginfo.id;
1998 if (e_dialinginfo.id[0]) {
1999 set_tone(portlist, "dialing");
2002 set_tone(portlist, "dialpbx");
2005 } else { /* testcall */
2006 set_tone(portlist, "hold");
2009 /* start recording if enabled, not when answering machine answers */
2010 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)) {
2011 /* check if we are a terminal */
2012 if (e_ext.number[0] == '\0')
2013 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2015 port = find_port_id(portlist->port_id);
2017 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2022 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2023 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2025 struct lcr_msg *message;
2027 unsigned int port_id = portlist->port_id;
2031 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2033 /* signal to call tool */
2034 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2036 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2037 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2038 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2043 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);
2044 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2045 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2047 /* check if we have more than one portlist relation and we just ignore the disconnect */
2048 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2049 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2050 portlist = ea_endpoint->ep_portlist;
2052 if (portlist->port_id == port_id)
2054 portlist = portlist->next;
2057 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2058 if (message_type != MESSAGE_RELEASE) {
2059 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2060 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2061 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2062 message_put(message);
2063 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2065 ea_endpoint->free_portlist(portlist);
2066 return; /* one relation removed */
2068 if (e_state == EPOINT_STATE_CONNECT) {
2069 /* use cause from port after connect */
2070 cause = param->disconnectinfo.cause;
2071 location = param->disconnectinfo.location;
2073 /* use multipoint cause if no connect yet */
2074 if (e_multipoint_cause) {
2075 cause = e_multipoint_cause;
2076 location = e_multipoint_location;
2078 cause = CAUSE_NOUSER;
2079 location = LOCATION_PRIVATE_LOCAL;
2083 unsched_timer(&e_cfnr_timeout);
2084 unsched_timer(&e_cfnr_call_timeout);
2086 /* process hangup */
2087 process_hangup(e_join_cause, e_join_location);
2088 e_multipoint_cause = 0;
2089 e_multipoint_location = 0;
2091 if (message_type == MESSAGE_DISCONNECT) {
2092 /* tone to disconnected end */
2093 SPRINT(buffer, "cause_%02x", cause);
2094 if (ea_endpoint->ep_portlist)
2095 set_tone(ea_endpoint->ep_portlist, buffer);
2097 new_state(EPOINT_STATE_IN_DISCONNECT);
2100 if (ea_endpoint->ep_join_id) {
2101 int haspatterns = 0;
2102 /* check if pattern is available */
2103 if (ea_endpoint->ep_portlist)
2104 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2105 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
2106 && message_type != MESSAGE_RELEASE) // if we release, we are done
2109 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2110 /* indicate patterns */
2111 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2112 message_put(message);
2113 /* connect audio, if not already */
2114 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2115 message->param.audiopath = 1;
2116 message_put(message);
2117 /* send disconnect */
2118 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2119 memcpy(&message->param, param, sizeof(union parameter));
2120 message_put(message);
2121 /* disable encryption if disconnected */
2122 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2125 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2129 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2132 if (message_type == MESSAGE_RELEASE)
2133 ea_endpoint->free_portlist(portlist);
2134 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2135 return; /* must exit here */
2138 /* port MESSAGE_TIMEOUT */
2139 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2143 trace_header("TIMEOUT", DIRECTION_IN);
2144 message_type = MESSAGE_DISCONNECT;
2145 switch (param->state) {
2146 case PORT_STATE_OUT_SETUP:
2147 case PORT_STATE_OUT_OVERLAP:
2148 add_trace("state", NULL, "outgoing setup/dialing");
2150 /* no user responding */
2151 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2152 return; /* must exit here */
2154 case PORT_STATE_IN_SETUP:
2155 case PORT_STATE_IN_OVERLAP:
2156 add_trace("state", NULL, "incoming setup/dialing");
2157 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2158 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2161 case PORT_STATE_OUT_PROCEEDING:
2162 add_trace("state", NULL, "outgoing proceeding");
2164 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2165 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2166 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2167 return; /* must exit here */
2169 case PORT_STATE_IN_PROCEEDING:
2170 add_trace("state", NULL, "incoming proceeding");
2171 param->disconnectinfo.cause = CAUSE_NOUSER;
2172 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2175 case PORT_STATE_OUT_ALERTING:
2176 add_trace("state", NULL, "outgoing alerting");
2178 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2179 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2180 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2181 return; /* must exit here */
2183 case PORT_STATE_CONNECT:
2184 add_trace("state", NULL, "connect");
2186 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2187 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2188 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2189 return; /* must exit here */
2191 case PORT_STATE_IN_ALERTING:
2192 add_trace("state", NULL, "incoming alerting");
2193 param->disconnectinfo.cause = CAUSE_NOANSWER;
2194 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2197 case PORT_STATE_IN_DISCONNECT:
2198 case PORT_STATE_OUT_DISCONNECT:
2199 add_trace("state", NULL, "disconnect");
2201 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2202 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2203 return; /* must exit here */
2206 param->disconnectinfo.cause = 31; /* normal unspecified */
2207 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2210 /* release call, disconnect isdn */
2212 new_state(EPOINT_STATE_OUT_DISCONNECT);
2213 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2214 SCPY(e_tone, cause);
2216 set_tone(portlist, cause);
2217 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2218 portlist = portlist->next;
2220 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2223 /* port MESSAGE_NOTIFY */
2224 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2226 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2228 struct lcr_msg *message;
2229 const char *logtext = "";
2232 /* signal to call tool */
2233 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);
2234 if (param->notifyinfo.notify) {
2235 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2238 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2239 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2240 case INFO_NOTIFY_REMOTE_HOLD:
2241 case INFO_NOTIFY_USER_SUSPENDED:
2242 /* tell call about it */
2243 if (ea_endpoint->ep_join_id) {
2244 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2245 message->param.audiopath = 0;
2246 message_put(message);
2250 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2251 case INFO_NOTIFY_USER_RESUMED:
2252 /* set volume of rx and tx */
2253 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2254 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2256 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2257 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2258 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2259 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2260 message_put(message);
2262 /* set current tone */
2264 set_tone(portlist, e_tone);
2265 /* tell call about it */
2266 if (ea_endpoint->ep_join_id) {
2267 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2268 message->param.audiopath = 1;
2269 message_put(message);
2274 /* get name of notify */
2275 switch(param->notifyinfo.notify) {
2280 logtext = "USER_SUSPENDED";
2283 logtext = "BEARER_SERVICE_CHANGED";
2286 logtext = "USER_RESUMED";
2289 logtext = "CONFERENCE_ESTABLISHED";
2292 logtext = "CONFERENCE_DISCONNECTED";
2295 logtext = "OTHER_PARTY_ADDED";
2298 logtext = "ISOLATED";
2301 logtext = "REATTACHED";
2304 logtext = "OTHER_PARTY_ISOLATED";
2307 logtext = "OTHER_PARTY_REATTACHED";
2310 logtext = "OTHER_PARTY_SPLIT";
2313 logtext = "OTHER_PARTY_DISCONNECTED";
2316 logtext = "CONFERENCE_FLOATING";
2319 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2322 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2325 logtext = "CALL_IS_A_WAITING_CALL";
2328 logtext = "DIVERSION_ACTIVATED";
2331 logtext = "RESERVED_CT_1";
2334 logtext = "RESERVED_CT_2";
2337 logtext = "REVERSE_CHARGING";
2340 logtext = "REMOTE_HOLD";
2343 logtext = "REMOTE_RETRIEVAL";
2346 logtext = "CALL_IS_DIVERTING";
2349 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2354 /* notify call if available */
2355 if (ea_endpoint->ep_join_id) {
2356 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2357 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2358 message_put(message);
2363 /* port MESSAGE_PROGRESS */
2364 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2366 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2368 struct lcr_msg *message;
2370 /* signal to call tool */
2371 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2373 /* send progress to call if available */
2374 if (ea_endpoint->ep_join_id) {
2375 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2376 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2377 message_put(message);
2382 /* port MESSAGE_FACILITY */
2383 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2385 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2387 struct lcr_msg *message;
2389 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2390 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2391 message_put(message);
2394 /* port MESSAGE_SUSPEND */
2395 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2396 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2398 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2400 /* epoint is now parked */
2401 ea_endpoint->ep_park = 1;
2402 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2403 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2405 /* remove port relation */
2406 ea_endpoint->free_portlist(portlist);
2409 /* port MESSAGE_RESUME */
2410 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2411 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2413 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2415 /* epoint is now resumed */
2416 ea_endpoint->ep_park = 0;
2420 /* port MESSAGE_ENABLEKEYPAD */
2421 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2423 struct lcr_msg *message;
2425 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2427 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2428 memcpy(&message->param, param, sizeof(union parameter));
2429 message_put(message);
2433 /* port sends message to the endpoint
2435 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2437 struct port_list *portlist;
2439 portlist = ea_endpoint->ep_portlist;
2441 if (port_id == portlist->port_id)
2443 portlist = portlist->next;
2446 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);
2450 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2451 switch(message_type) {
2452 case MESSAGE_TONE_EOF: /* tone is end of file */
2453 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2455 if (e_action->index == ACTION_VBOX_PLAY) {
2458 if (e_action->index == ACTION_EFI) {
2464 case MESSAGE_TONE_COUNTER: /* counter info received */
2465 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);
2467 if (e_action->index == ACTION_VBOX_PLAY) {
2468 e_vbox_counter = param->counter.current;
2469 if (param->counter.max >= 0)
2470 e_vbox_counter_max = param->counter.max;
2474 /* PORT sends SETUP message */
2476 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);
2477 if (e_state!=EPOINT_STATE_IDLE) {
2478 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2481 port_setup(portlist, message_type, param);
2484 /* PORT sends INFORMATION message */
2485 case MESSAGE_INFORMATION: /* additional digits received */
2486 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);
2487 port_information(portlist, message_type, param);
2490 /* PORT sends FACILITY message */
2491 case MESSAGE_FACILITY:
2492 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2493 port_facility(portlist, message_type, param);
2496 /* PORT sends DTMF message */
2497 case MESSAGE_DTMF: /* dtmf digits received */
2498 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);
2499 port_dtmf(portlist, message_type, param);
2502 /* PORT sends CRYPT message */
2503 case MESSAGE_CRYPT: /* crypt response received */
2504 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2505 port_crypt(portlist, message_type, param);
2508 /* PORT sends MORE message */
2509 case MESSAGE_OVERLAP:
2510 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);
2511 if (e_state != EPOINT_STATE_OUT_SETUP) {
2512 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);
2515 port_overlap(portlist, message_type, param);
2518 /* PORT sends PROCEEDING message */
2519 case MESSAGE_PROCEEDING: /* port is proceeding */
2520 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);
2521 if (e_state!=EPOINT_STATE_OUT_SETUP
2522 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2523 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);
2526 port_proceeding(portlist, message_type, param);
2529 /* PORT sends ALERTING message */
2530 case MESSAGE_ALERTING:
2531 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);
2532 if (e_state!=EPOINT_STATE_OUT_SETUP
2533 && e_state!=EPOINT_STATE_OUT_OVERLAP
2534 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2535 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);
2538 port_alerting(portlist, message_type, param);
2541 /* PORT sends CONNECT message */
2542 case MESSAGE_CONNECT:
2543 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);
2544 if (e_state!=EPOINT_STATE_OUT_SETUP
2545 && e_state!=EPOINT_STATE_OUT_OVERLAP
2546 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2547 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2548 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2551 port_connect(portlist, message_type, param);
2554 /* PORT sends DISCONNECT message */
2555 case MESSAGE_DISCONNECT: /* port is disconnected */
2556 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);
2557 port_disconnect_release(portlist, message_type, param);
2560 /* PORT sends a RELEASE message */
2561 case MESSAGE_RELEASE: /* port releases */
2562 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);
2563 /* portlist is release at port_disconnect_release, thanx Paul */
2564 port_disconnect_release(portlist, message_type, param);
2567 /* PORT sends a TIMEOUT message */
2568 case MESSAGE_TIMEOUT:
2569 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);
2570 port_timeout(portlist, message_type, param);
2571 break; /* release */
2573 /* PORT sends a NOTIFY message */
2574 case MESSAGE_NOTIFY:
2575 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);
2576 port_notify(portlist, message_type, param);
2579 /* PORT sends a PROGRESS message */
2580 case MESSAGE_PROGRESS:
2581 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);
2582 port_progress(portlist, message_type, param);
2585 /* PORT sends a SUSPEND message */
2586 case MESSAGE_SUSPEND:
2587 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);
2588 port_suspend(portlist, message_type, param);
2589 break; /* suspend */
2591 /* PORT sends a RESUME message */
2592 case MESSAGE_RESUME:
2593 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);
2594 port_resume(portlist, message_type, param);
2598 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2599 /* port assigns bchannel */
2600 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2601 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);
2602 /* only one port is expected to be connected to bchannel */
2603 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2604 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2608 /* PORT requests DTMF */
2609 case MESSAGE_ENABLEKEYPAD:
2610 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);
2611 port_enablekeypad(portlist, message_type, param);
2616 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);
2619 /* Note: this endpoint may be destroyed, so we MUST return */
2623 /* messages from join
2625 /* join MESSAGE_CRYPT */
2626 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2629 switch(param->crypt.type) {
2630 /* message from remote port to "crypt manager" */
2631 case CU_ACTK_REQ: /* activate key-exchange */
2632 case CU_ACTS_REQ: /* activate shared key */
2633 case CU_DACT_REQ: /* deactivate */
2634 case CU_INFO_REQ: /* request last info message */
2635 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2638 /* message from "crypt manager" to user */
2639 case CU_ACTK_CONF: /* key-echange done */
2640 case CU_ACTS_CONF: /* shared key done */
2641 case CU_DACT_CONF: /* deactivated */
2642 case CU_DACT_IND: /* deactivated */
2643 case CU_ERROR_IND: /* receive error message */
2644 case CU_INFO_IND: /* receive info message */
2645 case CU_INFO_CONF: /* receive info message */
2646 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2650 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);
2655 /* join MESSAGE_INFORMATION */
2656 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2658 struct lcr_msg *message;
2663 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2664 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2665 message_put(message);
2666 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2667 portlist = portlist->next;
2671 /* join MESSAGE_FACILITY */
2672 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2674 struct lcr_msg *message;
2676 if (!e_ext.facility && e_ext.number[0]) {
2681 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2682 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2683 message_put(message);
2684 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2685 portlist = portlist->next;
2689 /* join MESSAGE_MORE */
2690 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2692 struct lcr_msg *message;
2694 new_state(EPOINT_STATE_IN_OVERLAP);
2697 if (e_join_pattern && e_ext.own_setup) {
2698 /* disconnect audio */
2699 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2700 message->param.audiopath = 0;
2701 message_put(message);
2703 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2704 if (e_dialinginfo.id[0])
2705 set_tone(portlist, "dialing");
2707 set_tone(portlist, "dialtone");
2710 if (e_dialinginfo.id[0]) {
2711 set_tone(portlist, "dialing");
2713 if (e_ext.number[0])
2714 set_tone(portlist, "dialpbx");
2716 set_tone(portlist, "dialtone");
2720 /* join MESSAGE_PROCEEDING */
2721 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2723 struct lcr_msg *message;
2725 new_state(EPOINT_STATE_IN_PROCEEDING);
2727 /* own proceeding tone */
2728 if (e_join_pattern) {
2729 /* connect / disconnect audio */
2730 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2731 if (e_ext.own_proceeding)
2732 message->param.audiopath = 0;
2734 message->param.audiopath = 1;
2735 message_put(message);
2737 // UCPY(e_join_tone, "proceeding");
2739 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2740 message_put(message);
2741 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2743 set_tone(portlist, "proceeding");
2746 /* join MESSAGE_ALERTING */
2747 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2749 struct lcr_msg *message;
2751 new_state(EPOINT_STATE_IN_ALERTING);
2753 /* own alerting tone */
2754 if (e_join_pattern) {
2755 /* connect / disconnect audio */
2756 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2757 if (e_ext.own_alerting)
2758 message->param.audiopath = 0;
2760 message->param.audiopath = 1;
2761 message_put(message);
2764 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2765 message_put(message);
2766 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2768 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2769 set_tone(portlist, "ringing");
2772 if (e_ext.number[0])
2773 set_tone(portlist, "ringpbx");
2775 set_tone(portlist, "ringing");
2777 if (e_ext.number[0])
2778 e_dtmf = 1; /* allow dtmf */
2781 /* join MESSAGE_CONNECT */
2782 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2784 struct lcr_msg *message;
2787 new_state(EPOINT_STATE_CONNECT);
2788 // UCPY(e_join_tone, "");
2790 if (e_ext.number[0])
2791 e_dtmf = 1; /* allow dtmf */
2794 unsched_timer(&e_powerdial_timeout);
2795 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2797 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2798 memcpy(&message->param, param, sizeof(union parameter));
2800 /* screen clip if prefix is required */
2801 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2802 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2803 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2804 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2807 /* use internal caller id */
2808 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2809 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2810 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2813 /* handle restricted caller ids */
2814 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);
2815 /* display callerid if desired for extension */
2816 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));
2818 /* use conp, if enabld */
2819 // if (!e_ext.centrex)
2820 // message->param.connectinfo.name[0] = '\0';
2823 message_put(message);
2824 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2826 set_tone(portlist, NULL);
2828 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2829 message->param.audiopath = 1;
2830 message_put(message);
2835 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2836 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2839 struct lcr_msg *message;
2840 struct port_list *portlist = NULL;
2844 /* be sure that we are active */
2846 e_tx_state = NOTIFY_STATE_ACTIVE;
2848 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2849 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2850 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2852 /* set time for power dialing */
2853 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2856 /* set redial tone */
2857 if (ea_endpoint->ep_portlist) {
2860 set_tone(ea_endpoint->ep_portlist, "redial");
2861 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);
2862 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2863 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2864 new_state(EPOINT_STATE_IN_PROCEEDING);
2865 if (ea_endpoint->ep_portlist) {
2866 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2867 message_put(message);
2868 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2870 /* caused the error, that the first knock sound was not there */
2871 /* set_tone(portlist, "proceeding"); */
2873 /* send display of powerdialing */
2874 if (e_ext.display_dialing) {
2875 portlist = ea_endpoint->ep_portlist;
2877 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2879 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2881 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2882 message_put(message);
2883 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2884 portlist = portlist->next;
2894 if ((e_state!=EPOINT_STATE_CONNECT
2895 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2896 && e_state!=EPOINT_STATE_IN_OVERLAP
2897 && e_state!=EPOINT_STATE_IN_PROCEEDING
2898 && e_state!=EPOINT_STATE_IN_ALERTING)
2899 || !ea_endpoint->ep_portlist) { /* or no port */
2900 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2901 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2902 return; /* must exit here */
2905 if (!e_join_cause) {
2906 e_join_cause = param->disconnectinfo.cause;
2907 e_join_location = param->disconnectinfo.location;
2910 /* on release we need the audio again! */
2911 if (message_type == MESSAGE_RELEASE) {
2913 ea_endpoint->ep_join_id = 0;
2915 /* disconnect and select tone */
2916 new_state(EPOINT_STATE_OUT_DISCONNECT);
2917 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2918 /* if own_cause, we must release the join */
2919 if (e_ext.own_cause /* own cause */
2920 || !e_join_pattern) { /* no patterns */
2921 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);
2922 if (message_type != MESSAGE_RELEASE)
2923 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2925 } else { /* else we enable audio */
2926 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2927 message->param.audiopath = 1;
2928 message_put(message);
2930 /* send disconnect message */
2931 SCPY(e_tone, cause);
2932 portlist = ea_endpoint->ep_portlist;
2934 set_tone(portlist, cause);
2935 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2936 portlist = portlist->next;
2940 /* join MESSAGE_SETUP */
2941 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2943 struct lcr_msg *message;
2944 // struct interface *interface;
2946 /* if we already in setup state, we just update the dialing with new digits */
2947 if (e_state == EPOINT_STATE_OUT_SETUP
2948 || e_state == EPOINT_STATE_OUT_OVERLAP) {
2949 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
2950 /* if digits changed, what we have already dialed */
2951 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
2952 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);
2953 /* release all ports */
2954 while((portlist = ea_endpoint->ep_portlist)) {
2955 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2956 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2957 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2958 message_put(message);
2959 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2960 ea_endpoint->free_portlist(portlist);
2963 /* disconnect audio */
2964 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2965 message->param.audiopath = 0;
2966 message_put(message);
2968 /* get dialing info */
2969 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
2970 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2971 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
2972 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
2973 new_state(EPOINT_STATE_OUT_OVERLAP);
2976 schedule_timer(&e_redial_timeout, 1, 0);
2979 /* if we have a pending redial, so we just adjust the dialing number */
2980 if (e_redial_timeout.active) {
2981 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);
2982 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2985 if (!ea_endpoint->ep_portlist) {
2986 PERROR("ERROR: overlap dialing to a NULL port relation\n");
2988 if (ea_endpoint->ep_portlist->next) {
2989 PERROR("ERROR: overlap dialing to a port_list port relation\n");
2991 if (e_state == EPOINT_STATE_OUT_SETUP) {
2993 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);
2994 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2997 /* get what we have not dialed yet */
2998 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));
2999 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3000 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3001 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3002 message_put(message);
3003 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3005 /* always store what we have dialed or queued */
3006 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3010 if (e_state != EPOINT_STATE_IDLE) {
3011 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3014 /* if an internal extension is dialed, copy that number */
3015 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3016 SCPY(e_ext.number, param->setup.dialinginfo.id);
3017 /* if an internal extension is dialed, get extension's info about caller */
3018 if (e_ext.number[0]) {
3019 if (!read_extension(&e_ext, e_ext.number)) {
3020 e_ext.number[0] = '\0';
3021 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3025 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3026 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3027 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3028 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3029 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3031 /* process (voice over) data calls */
3032 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3033 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3034 memset(&e_capainfo, 0, sizeof(e_capainfo));
3035 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3036 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3037 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3040 new_state(EPOINT_STATE_OUT_SETUP);
3041 /* call special setup routine */
3045 /* join MESSAGE_mISDNSIGNAL */
3046 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3048 struct lcr_msg *message;
3051 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3052 memcpy(&message->param, param, sizeof(union parameter));
3053 message_put(message);
3054 portlist = portlist->next;
3058 /* join MESSAGE_BRIDE */
3059 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3061 struct lcr_msg *message;
3064 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3065 memcpy(&message->param, param, sizeof(union parameter));
3066 message_put(message);
3067 portlist = portlist->next;
3071 /* join MESSAGE_NOTIFY */
3072 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3074 struct lcr_msg *message;
3077 if (param->notifyinfo.notify) {
3078 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3079 // /* if notification was generated locally, we turn hold music on/off */
3080 // if (param->notifyinfo.local)
3081 // 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)
3085 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3086 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3088 set_tone(portlist, "");
3089 portlist = portlist->next;
3092 portlist = ea_endpoint->ep_portlist;
3097 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3099 set_tone(portlist, "hold");
3100 portlist = portlist->next;
3102 portlist = ea_endpoint->ep_portlist;
3107 /* save new state */
3108 e_tx_state = new_state;
3111 /* notify port(s) about it */
3113 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3114 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3115 /* handle restricted caller ids */
3116 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3117 /* display callerid if desired for extension */
3118 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));
3119 message_put(message);
3120 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3121 portlist = portlist->next;
3125 /* join MESSAGE_DTMF */
3126 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3128 struct lcr_msg *message;
3131 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3132 memcpy(&message->param, param, sizeof(union parameter));
3133 message_put(message);
3134 portlist = portlist->next;
3138 /* JOIN sends messages to the endpoint
3140 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3142 struct port_list *portlist;
3143 struct lcr_msg *message;
3146 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3150 portlist = ea_endpoint->ep_portlist;
3152 // 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);
3153 switch(message_type) {
3154 /* JOIN SENDS TONE message */
3156 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);
3157 set_tone(portlist, param->tone.name);
3160 /* JOIN SENDS CRYPT message */
3162 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);
3163 join_crypt(portlist, message_type, param);
3166 /* JOIN sends INFORMATION message */
3167 case MESSAGE_INFORMATION:
3168 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);
3169 join_information(portlist, message_type, param);
3172 /* JOIN sends FACILITY message */
3173 case MESSAGE_FACILITY:
3174 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);
3175 join_facility(portlist, message_type, param);
3178 /* JOIN sends OVERLAP message */
3179 case MESSAGE_OVERLAP:
3180 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);
3181 if (e_state!=EPOINT_STATE_IN_SETUP
3182 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3183 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3186 join_overlap(portlist, message_type, param);
3189 /* JOIN sends PROCEEDING message */
3190 case MESSAGE_PROCEEDING:
3191 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);
3192 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3193 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3196 join_proceeding(portlist, message_type, param);
3199 /* JOIN sends ALERTING message */
3200 case MESSAGE_ALERTING:
3201 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);
3202 if (e_state!=EPOINT_STATE_IN_OVERLAP
3203 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3204 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3207 join_alerting(portlist, message_type, param);
3210 /* JOIN sends CONNECT message */
3211 case MESSAGE_CONNECT:
3212 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);
3213 if (e_state!=EPOINT_STATE_IN_OVERLAP
3214 && e_state!=EPOINT_STATE_IN_PROCEEDING
3215 && e_state!=EPOINT_STATE_IN_ALERTING) {
3216 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3219 join_connect(portlist, message_type, param);
3222 /* JOIN sends DISCONNECT/RELEASE message */
3223 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3224 case MESSAGE_RELEASE: /* JOIN releases */
3225 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);
3226 join_disconnect_release(message_type, param);
3229 /* JOIN sends SETUP message */
3231 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);
3232 join_setup(portlist, message_type, param);
3235 /* JOIN sends special mISDNSIGNAL message */
3236 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3237 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);
3238 join_mISDNsignal(portlist, message_type, param);
3241 /* JOIN sends bridge message */
3242 case MESSAGE_BRIDGE: /* bride message to port */
3243 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);
3244 join_bridge(portlist, message_type, param);
3247 /* JOIN has pattern available */
3248 case MESSAGE_PATTERN: /* indicating pattern available */
3249 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);
3250 if (!e_join_pattern) {
3251 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3255 set_tone(portlist, NULL);
3256 portlist = portlist->next;
3258 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3259 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3260 message->param.audiopath = 1;
3261 message_put(message);
3265 /* JOIN has no pattern available */
3266 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3267 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);
3268 if (e_join_pattern) {
3269 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3271 /* disconnect our audio tx and rx */
3272 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3273 message->param.audiopath = 0;
3274 message_put(message);
3279 /* JOIN (dunno at the moment) */
3280 case MESSAGE_REMOTE_AUDIO:
3281 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);
3282 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3283 message->param.audiopath = param->channel;
3284 message_put(message);
3288 /* JOIN sends a notify message */
3289 case MESSAGE_NOTIFY:
3290 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);
3291 join_notify(portlist, message_type, param);
3294 /* JOIN wants keypad / dtmf */
3295 case MESSAGE_ENABLEKEYPAD:
3296 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);
3299 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3303 /* JOIN sends a DTMF message */
3305 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);
3306 join_dtmf(portlist, message_type, param);
3310 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);
3315 /* pick_join will connect the first incoming call found. the endpoint
3316 * will receivce a MESSAGE_CONNECT.
3318 int match_list(char *list, char *item)
3320 char *end, *next = NULL;
3322 /* no list make matching */
3327 /* eliminate white spaces */
3328 while (*list > '\0' && *list <= ' ')
3334 /* if end of list is reached, we return */
3335 if (list[0] == '\0')
3337 /* if we have more than one entry (left) */
3338 if ((end = strchr(list, ',')))
3341 next = end = strchr(list, '\0');
3342 while (*(end-1) <= ' ')
3344 /* if string part matches item */
3345 if (!strncmp(list, item, end-list))
3351 void EndpointAppPBX::pick_join(char *extensions)
3353 struct lcr_msg *message;
3354 struct port_list *portlist;
3356 class EndpointAppPBX *eapp, *found;
3358 class JoinPBX *joinpbx;
3359 struct join_relation *relation;
3362 /* find an endpoint that is ringing internally or vbox with higher priority */
3365 eapp = apppbx_first;
3367 if (eapp!=this && ea_endpoint->ep_portlist) {
3368 portlist = eapp->ea_endpoint->ep_portlist;
3370 if ((port = find_port_id(portlist->port_id))) {
3371 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3372 if (match_list(extensions, eapp->e_ext.number)) {
3378 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3379 && port->p_state==PORT_STATE_OUT_ALERTING)
3380 if (match_list(extensions, eapp->e_ext.number)) {
3384 portlist = portlist->next;
3392 /* if no endpoint found */
3394 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);
3396 set_tone(ea_endpoint->ep_portlist, "cause_10");
3397 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3398 new_state(EPOINT_STATE_OUT_DISCONNECT);
3403 if (ea_endpoint->ep_join_id) {
3404 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3407 if (!eapp->ea_endpoint->ep_join_id) {
3408 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3411 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3413 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3416 if (join->j_type != JOIN_TYPE_PBX) {
3417 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3420 joinpbx = (class JoinPBX *)join;
3421 relation = joinpbx->j_relation;
3423 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3426 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3427 relation = relation->next;
3429 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3434 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3436 if (options.deb & DEBUG_EPOINT) {
3437 class Join *debug_c = join_first;
3438 class Endpoint *debug_e = epoint_first;
3439 class Port *debug_p = port_first;
3441 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3443 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3445 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3446 debug_c = debug_c->next;
3448 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3450 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3451 debug_e = debug_e->next;
3453 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3455 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3456 debug_p = debug_p->next;
3461 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3462 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3463 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3465 /* connnecting our endpoint */
3466 new_state(EPOINT_STATE_CONNECT);
3467 if (e_ext.number[0])
3469 set_tone(ea_endpoint->ep_portlist, NULL);
3471 /* now we send a release to the ringing endpoint */
3472 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3473 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3474 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3475 message_put(message);
3477 /* we send a connect to the join with our caller id */
3478 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3479 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3480 message->param.connectinfo.present = e_callerinfo.present;
3481 message->param.connectinfo.screen = e_callerinfo.screen;
3482 message->param.connectinfo.itype = e_callerinfo.itype;
3483 message->param.connectinfo.ntype = e_callerinfo.ntype;
3484 message_put(message);
3486 /* we send a connect to our port with the remote callerid */
3487 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3488 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3489 message->param.connectinfo.present = eapp->e_callerinfo.present;
3490 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3491 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3492 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3493 /* handle restricted caller ids */
3494 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);
3495 /* display callerid if desired for extension */
3496 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));
3497 message_put(message);
3499 /* we send a connect to the audio path (not for vbox) */
3500 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3501 message->param.audiopath = 1;
3502 message_put(message);
3504 /* beeing paranoid, we make call update */
3505 trigger_work(&joinpbx->j_updatebridge);
3507 if (options.deb & DEBUG_EPOINT) {
3508 class Join *debug_c = join_first;
3509 class Endpoint *debug_e = epoint_first;
3510 class Port *debug_p = port_first;
3512 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3514 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3516 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3517 debug_c = debug_c->next;
3519 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3521 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3522 debug_e = debug_e->next;
3524 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3526 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3527 debug_p = debug_p->next;
3533 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3535 void EndpointAppPBX::join_join(void)
3538 struct lcr_msg *message;
3539 struct join_relation *our_relation, *other_relation;
3540 struct join_relation **our_relation_pointer, **other_relation_pointer;
3541 class Join *our_join, *other_join;
3542 class JoinPBX *our_joinpbx, *other_joinpbx;
3543 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3544 class Port *our_port, *other_port;
3545 class Pdss1 *our_pdss1, *other_pdss1;
3547 /* are we a candidate to join a join? */
3548 our_join = find_join_id(ea_endpoint->ep_join_id);
3550 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3553 if (our_join->j_type != JOIN_TYPE_PBX) {
3554 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3557 our_joinpbx = (class JoinPBX *)our_join;
3558 if (!ea_endpoint->ep_portlist) {
3559 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3562 if (!e_ext.number[0]) {
3563 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3566 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3568 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3571 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3572 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3575 our_pdss1 = (class Pdss1 *)our_port;
3577 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3578 other_eapp = apppbx_first;
3580 if (other_eapp == this) {
3581 other_eapp = other_eapp->next;
3584 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);
3585 if (other_eapp->e_ext.number[0] /* has terminal */
3586 && other_eapp->ea_endpoint->ep_portlist /* has port */
3587 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3588 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3589 if (other_port) { /* port still exists */
3590 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3591 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3592 other_pdss1 = (class Pdss1 *)other_port;
3593 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);
3594 if (other_pdss1->p_m_hold /* port is on hold */
3595 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3596 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3599 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3602 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3605 other_eapp = other_eapp->next;
3608 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3611 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3613 /* if we have the same join */
3614 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3615 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3618 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3620 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3623 if (other_join->j_type != JOIN_TYPE_PBX) {
3624 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3627 other_joinpbx = (class JoinPBX *)other_join;
3628 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3629 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3633 /* remove relation to endpoint for join on hold */
3634 other_relation = other_joinpbx->j_relation;
3635 other_relation_pointer = &other_joinpbx->j_relation;
3636 while(other_relation) {
3637 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3638 /* detach other endpoint on hold */
3639 *other_relation_pointer = other_relation->next;
3640 FREE(other_relation, sizeof(struct join_relation));
3642 other_relation = *other_relation_pointer;
3643 other_eapp->ea_endpoint->ep_join_id = 0;
3647 /* change join/hold pointer of endpoint to the new join */
3648 temp_epoint = find_epoint_id(other_relation->epoint_id);
3650 if (temp_epoint->ep_join_id == other_join->j_serial)
3651 temp_epoint->ep_join_id = our_join->j_serial;
3654 other_relation_pointer = &other_relation->next;
3655 other_relation = other_relation->next;
3657 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3659 /* join call relations */
3660 our_relation = our_joinpbx->j_relation;
3661 our_relation_pointer = &our_joinpbx->j_relation;
3662 while(our_relation) {
3663 our_relation_pointer = &our_relation->next;
3664 our_relation = our_relation->next;
3666 *our_relation_pointer = other_joinpbx->j_relation;
3667 other_joinpbx->j_relation = NULL;
3668 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3670 /* release endpoint on hold */
3671 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3672 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3673 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3674 message_put(message);
3676 /* if we are not a partyline, we get partyline state from other join */
3677 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3679 /* remove empty join */
3681 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3683 /* mixer must update */
3684 trigger_work(&our_joinpbx->j_updatebridge);
3686 /* we send a retrieve to that endpoint */
3687 // mixer will update the hold-state of the join and send it to the endpoints is changes
3689 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3694 /* check if we have an external call
3695 * this is used to check for encryption ability
3697 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3699 struct join_relation *relation;
3701 class JoinPBX *joinpbx;
3702 class Endpoint *epoint;
3704 /* some paranoia check */
3705 if (!ea_endpoint->ep_portlist) {
3706 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3707 *errstr = "No Call";
3710 if (!e_ext.number[0]) {
3711 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3712 *errstr = "No Call";
3716 /* check if we have a join with 2 parties */
3717 join = find_join_id(ea_endpoint->ep_join_id);
3719 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3720 *errstr = "No Call";
3723 if (join->j_type != JOIN_TYPE_PBX) {
3724 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3725 *errstr = "No PBX Call";
3728 joinpbx = (class JoinPBX *)join;
3729 relation = joinpbx->j_relation;
3731 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3732 *errstr = "No Call";
3735 if (!relation->next) {
3736 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3737 *errstr = "No Call";
3740 if (relation->next->next) {
3741 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3742 *errstr = "Err: Conference";
3745 if (relation->epoint_id == ea_endpoint->ep_serial) {
3746 relation = relation->next;
3747 if (relation->epoint_id == ea_endpoint->ep_serial) {
3748 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3749 *errstr = "Software Error";
3754 /* check remote port for external call */
3755 epoint = find_epoint_id(relation->epoint_id);
3757 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3758 *errstr = "No Call";
3761 if (!epoint->ep_portlist) {
3762 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3763 *errstr = "No Call";
3766 *port = find_port_id(epoint->ep_portlist->port_id);
3768 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3769 *errstr = "No Call";
3772 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
3773 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3774 *errstr = "No Ext Call";
3777 if ((*port)->p_state != PORT_STATE_CONNECT) {
3778 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3779 *errstr = "No Ext Connect";
3785 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3787 const char *logtext = "unknown";
3790 switch(message_type) {
3792 trace_header("SETUP", dir);
3793 if (dir == DIRECTION_OUT)
3794 add_trace("to", NULL, "CH(%lu)", port_id);
3795 if (dir == DIRECTION_IN)
3796 add_trace("from", NULL, "CH(%lu)", port_id);
3797 if (param->setup.callerinfo.extension[0])
3798 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3799 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3800 switch(param->setup.callerinfo.present) {
3801 case INFO_PRESENT_RESTRICTED:
3802 add_trace("caller id", "present", "restricted");
3804 case INFO_PRESENT_ALLOWED:
3805 add_trace("caller id", "present", "allowed");
3808 add_trace("caller id", "present", "not available");
3810 if (param->setup.callerinfo.ntype2) {
3811 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3812 switch(param->setup.callerinfo.present) {
3813 case INFO_PRESENT_RESTRICTED:
3814 add_trace("caller id2", "present", "restricted");
3816 case INFO_PRESENT_ALLOWED:
3817 add_trace("caller id2", "present", "allowed");
3820 add_trace("caller id2", "present", "not available");
3823 if (param->setup.redirinfo.id[0]) {
3824 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3825 switch(param->setup.redirinfo.present) {
3826 case INFO_PRESENT_RESTRICTED:
3827 add_trace("redir'ing", "present", "restricted");
3829 case INFO_PRESENT_ALLOWED:
3830 add_trace("redir'ing", "present", "allowed");
3833 add_trace("redir'ing", "present", "not available");
3836 if (param->setup.dialinginfo.id[0])
3837 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3838 if (param->setup.dialinginfo.keypad[0])
3839 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3840 if (param->setup.dialinginfo.display[0])
3841 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3842 if (param->setup.dialinginfo.sending_complete)
3843 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3847 case MESSAGE_OVERLAP:
3848 trace_header("SETUP ACKNOWLEDGE", dir);
3849 if (dir == DIRECTION_OUT)
3850 add_trace("to", NULL, "CH(%lu)", port_id);
3851 if (dir == DIRECTION_IN)
3852 add_trace("from", NULL, "CH(%lu)", port_id);
3856 case MESSAGE_PROCEEDING:
3857 trace_header("PROCEEDING", dir);
3858 if (dir == DIRECTION_OUT)
3859 add_trace("to", NULL, "CH(%lu)", port_id);
3860 if (dir == DIRECTION_IN)
3861 add_trace("from", NULL, "CH(%lu)", port_id);
3865 case MESSAGE_ALERTING:
3866 trace_header("ALERTING", dir);
3867 if (dir == DIRECTION_OUT)
3868 add_trace("to", NULL, "CH(%lu)", port_id);
3869 if (dir == DIRECTION_IN)
3870 add_trace("from", NULL, "CH(%lu)", port_id);
3874 case MESSAGE_CONNECT:
3875 trace_header("CONNECT", dir);
3876 if (dir == DIRECTION_OUT)
3877 add_trace("to", NULL, "CH(%lu)", port_id);
3878 if (dir == DIRECTION_IN)
3879 add_trace("from", NULL, "CH(%lu)", port_id);
3880 if (param->connectinfo.extension[0])
3881 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3882 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3883 switch(param->connectinfo.present) {
3884 case INFO_PRESENT_RESTRICTED:
3885 add_trace("connect id", "present", "restricted");
3887 case INFO_PRESENT_ALLOWED:
3888 add_trace("connect id", "present", "allowed");
3891 add_trace("connect id", "present", "not available");
3893 if (param->connectinfo.display[0])
3894 add_trace("display", NULL, "%s", param->connectinfo.display);
3898 case MESSAGE_DISCONNECT:
3899 case MESSAGE_RELEASE:
3900 if (message_type == MESSAGE_DISCONNECT)
3901 trace_header("DISCONNECT", dir);
3903 trace_header("RELEASE", dir);
3904 if (dir == DIRECTION_OUT)
3905 add_trace("to", NULL, "CH(%lu)", port_id);
3906 if (dir == DIRECTION_IN)
3907 add_trace("from", NULL, "CH(%lu)", port_id);
3908 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3909 switch(param->disconnectinfo.location) {
3911 add_trace("cause", "location", "0-User");
3913 case LOCATION_PRIVATE_LOCAL:
3914 add_trace("cause", "location", "1-Local-PBX");
3916 case LOCATION_PUBLIC_LOCAL:
3917 add_trace("cause", "location", "2-Local-Exchange");
3919 case LOCATION_TRANSIT:
3920 add_trace("cause", "location", "3-Transit");
3922 case LOCATION_PUBLIC_REMOTE:
3923 add_trace("cause", "location", "4-Remote-Exchange");
3925 case LOCATION_PRIVATE_REMOTE:
3926 add_trace("cause", "location", "5-Remote-PBX");
3928 case LOCATION_INTERNATIONAL:
3929 add_trace("cause", "location", "7-International-Exchange");
3931 case LOCATION_BEYOND:
3932 add_trace("cause", "location", "10-Beyond-Interworking");
3935 add_trace("cause", "location", "%d", param->disconnectinfo.location);
3937 if (param->disconnectinfo.display[0])
3938 add_trace("display", NULL, "%s", param->disconnectinfo.display);
3942 case MESSAGE_NOTIFY:
3943 switch(param->notifyinfo.notify) {
3948 logtext = "USER_SUSPENDED";
3951 logtext = "BEARER_SERVICE_CHANGED";
3954 logtext = "USER_RESUMED";
3957 logtext = "CONFERENCE_ESTABLISHED";
3960 logtext = "CONFERENCE_DISCONNECTED";
3963 logtext = "OTHER_PARTY_ADDED";
3966 logtext = "ISOLATED";
3969 logtext = "REATTACHED";
3972 logtext = "OTHER_PARTY_ISOLATED";
3975 logtext = "OTHER_PARTY_REATTACHED";
3978 logtext = "OTHER_PARTY_SPLIT";
3981 logtext = "OTHER_PARTY_DISCONNECTED";
3984 logtext = "CONFERENCE_FLOATING";
3987 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
3990 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
3993 logtext = "CALL_IS_A_WAITING_CALL";
3996 logtext = "DIVERSION_ACTIVATED";
3999 logtext = "RESERVED_CT_1";
4002 logtext = "RESERVED_CT_2";
4005 logtext = "REVERSE_CHARGING";
4008 logtext = "REMOTE_HOLD";
4011 logtext = "REMOTE_RETRIEVAL";
4014 logtext = "CALL_IS_DIVERTING";
4017 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4021 trace_header("NOTIFY", dir);
4022 if (dir == DIRECTION_OUT)
4023 add_trace("to", NULL, "CH(%lu)", port_id);
4024 if (dir == DIRECTION_IN)
4025 add_trace("from", NULL, "CH(%lu)", port_id);
4026 if (param->notifyinfo.notify)
4027 add_trace("indicator", NULL, "%s", logtext);
4028 if (param->notifyinfo.id[0]) {
4029 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4030 switch(param->notifyinfo.present) {
4031 case INFO_PRESENT_RESTRICTED:
4032 add_trace("redir'on", "present", "restricted");
4034 case INFO_PRESENT_ALLOWED:
4035 add_trace("redir'on", "present", "allowed");
4038 add_trace("redir'on", "present", "not available");
4041 if (param->notifyinfo.display[0])
4042 add_trace("display", NULL, "%s", param->notifyinfo.display);
4046 case MESSAGE_PROGRESS:
4047 switch(param->progressinfo.progress) {
4049 logtext = "Call is not end to end ISDN";
4052 logtext = "Destination address is non-ISDN";
4055 logtext = "Origination address is non-ISDN";
4058 logtext = "Call has returned to the ISDN";
4061 logtext = "In-band info or pattern available";
4064 SPRINT(buffer, "%d", param->progressinfo.progress);
4068 trace_header("PROGRESS", dir);
4069 if (dir == DIRECTION_OUT)
4070 add_trace("to", NULL, "CH(%lu)", port_id);
4071 if (dir == DIRECTION_IN)
4072 add_trace("from", NULL, "CH(%lu)", port_id);
4073 add_trace("indicator", NULL, "%s", logtext);
4074 switch(param->progressinfo.location) {
4076 add_trace("cause", "location", "0-User");
4078 case LOCATION_PRIVATE_LOCAL:
4079 add_trace("cause", "location", "1-Local-PBX");
4081 case LOCATION_PUBLIC_LOCAL:
4082 add_trace("cause", "location", "2-Local-Exchange");
4084 case LOCATION_TRANSIT:
4085 add_trace("cause", "location", "3-Transit");
4087 case LOCATION_PUBLIC_REMOTE:
4088 add_trace("cause", "location", "4-Remote-Exchange");
4090 case LOCATION_PRIVATE_REMOTE:
4091 add_trace("cause", "location", "5-Remote-PBX");
4093 case LOCATION_INTERNATIONAL:
4094 add_trace("cause", "location", "7-International-Exchange");
4096 case LOCATION_BEYOND:
4097 add_trace("cause", "location", "10-Beyond-Interworking");
4100 add_trace("cause", "location", "%d", param->progressinfo.location);
4105 case MESSAGE_INFORMATION:
4106 trace_header("INFORMATION", dir);
4107 if (dir == DIRECTION_OUT)
4108 add_trace("to", NULL, "CH(%lu)", port_id);
4109 if (dir == DIRECTION_IN)
4110 add_trace("from", NULL, "CH(%lu)", port_id);
4111 if (param->information.id[0])
4112 add_trace("dialing", NULL, "%s", param->information.id);
4113 if (param->information.display[0])
4114 add_trace("display", NULL, "%s", param->information.display);
4115 if (param->information.sending_complete)
4116 add_trace("complete", NULL, "true", param->information.sending_complete);
4120 case MESSAGE_FACILITY:
4121 trace_header("FACILITY", dir);
4122 if (dir == DIRECTION_OUT)
4123 add_trace("to", NULL, "CH(%lu)", port_id);
4124 if (dir == DIRECTION_IN)
4125 add_trace("from", NULL, "CH(%lu)", port_id);
4130 trace_header("TONE", dir);
4131 if (dir == DIRECTION_OUT)
4132 add_trace("to", NULL, "CH(%lu)", port_id);
4133 if (dir == DIRECTION_IN)
4134 add_trace("from", NULL, "CH(%lu)", port_id);
4135 if (param->tone.name[0]) {
4136 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4137 add_trace("name", NULL, "%s", param->tone.name);
4139 add_trace("off", NULL, NULL);
4143 case MESSAGE_SUSPEND:
4144 case MESSAGE_RESUME:
4145 if (message_type == MESSAGE_SUSPEND)
4146 trace_header("SUSPEND", dir);
4148 trace_header("RESUME", dir);
4149 if (dir == DIRECTION_OUT)
4150 add_trace("to", NULL, "CH(%lu)", port_id);
4151 if (dir == DIRECTION_IN)
4152 add_trace("from", NULL, "CH(%lu)", port_id);
4153 if (param->parkinfo.len)
4154 add_trace("length", NULL, "%d", param->parkinfo.len);
4159 case MESSAGE_BCHANNEL:
4160 trace_header("BCHANNEL", dir);
4161 switch(param->bchannel.type) {
4162 case BCHANNEL_REQUEST:
4163 add_trace("type", NULL, "request");
4165 case BCHANNEL_ASSIGN:
4166 add_trace("type", NULL, "assign");
4168 case BCHANNEL_ASSIGN_ACK:
4169 add_trace("type", NULL, "assign_ack");
4171 case BCHANNEL_REMOVE:
4172 add_trace("type", NULL, "remove");
4174 case BCHANNEL_REMOVE_ACK:
4175 add_trace("type", NULL, "remove_ack");
4178 if (param->bchannel.addr)
4179 add_trace("address", NULL, "%x", param->bchannel.addr);
4185 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4189 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4191 struct lcr_msg *message;
4195 if (!portlist->port_id)
4198 if (!e_connectedmode) {
4199 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4200 message->param.disconnectinfo.cause = cause;
4201 message->param.disconnectinfo.location = location;
4203 SCPY(message->param.disconnectinfo.display, display);
4205 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4207 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4209 SCPY(message->param.notifyinfo.display, display);
4211 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4213 message_put(message);
4214 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);