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)
505 /* we must be in a call, in order to send messages to the call */
506 if (e_ext.number[0] == '\0') {
507 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
512 /* join conference */
514 if (ea_endpoint->ep_join_id == 0) {
515 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
518 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
519 port = find_port_id(ea_endpoint->ep_portlist->port_id);
522 if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS)
524 else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1)
531 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
535 /* crypt key-exchange */
537 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
543 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
549 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
554 /* set tone pattern for port */
555 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
557 struct lcr_msg *message;
562 /* store for suspended processes */
566 if (e_join_pattern /* pattern are provided */
567 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
568 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
569 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
570 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
571 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
572 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
573 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
574 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
575 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
576 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
577 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
578 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
583 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
584 SCPY(message->param.tone.dir, e_ext.tones_dir);
585 SCPY(message->param.tone.name, tone);
586 message_put(message);
587 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
589 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
595 /* outgoing setup to port(s)
596 * ports will be created and a setup is sent if everything is ok. otherwhise
597 * the endpoint is destroyed.
599 void EndpointAppPBX::out_setup(int cfnr)
601 struct dialing_info dialinginfo;
603 struct port_list *portlist;
604 struct lcr_msg *message;
606 int cause = CAUSE_RESSOURCEUNAVAIL;
609 struct interface *interface;
611 struct mISDNport *mISDNport;
615 class EndpointAppPBX *atemp;
616 // char allowed_ports[256];
618 char ifname[sizeof(e_ext.interfaces)],
622 struct port_settings port_settings;
626 struct admin_list *admin;
628 int mode = B_MODE_TRANSPARENT;
630 /* set bchannel mode */
631 mode = e_capainfo.source_mode;
633 /* create settings for creating port */
634 memset(&port_settings, 0, sizeof(port_settings));
636 SCPY(port_settings.tones_dir, e_ext.tones_dir);
638 SCPY(port_settings.tones_dir, options.tones_dir);
639 port_settings.no_seconds = e_ext.no_seconds;
641 /* 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 */
643 /* check what dialinginfo.itype we got */
644 switch(e_dialinginfo.itype) {
645 /* *********************** call to extension or vbox */
646 case INFO_ITYPE_ISDN_EXTENSION:
647 /* check if we deny incoming calls when we use an extension */
648 if (e_ext.noknocking) {
649 atemp = apppbx_first;
652 if (!strcmp(atemp->e_ext.number, e_ext.number))
657 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
658 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
659 return; /* must exit here */
662 /* FALL THROUGH !!!! */
663 case INFO_ITYPE_VBOX:
664 /* get dialed extension's info */
665 // SCPY(exten, e_dialinginfo.id);
666 // if (strchr(exten, ','))
667 // *strchr(exten, ',') = '\0';
668 // if (!read_extension(&e_ext, exten))
669 if (!read_extension(&e_ext, e_dialinginfo.id)) {
670 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
671 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
672 return; /* must exit here */
674 e_dialinginfo.sending_complete = 1;
676 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
677 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
682 /* string from unconditional call forward (cfu) */
685 /* present to forwarded party */
686 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
687 e_callerinfo.present = INFO_PRESENT_ALLOWED;
689 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
693 /* string from busy call forward (cfb) */
696 class EndpointAppPBX *checkapp = apppbx_first;
698 if (checkapp != this) { /* any other endpoint except our own */
699 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
700 /* present to forwarded party */
701 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
702 e_callerinfo.present = INFO_PRESENT_ALLOWED;
704 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
708 checkapp = checkapp->next;
712 /* string from no-response call forward (cfnr) */
715 /* when cfnr is done, out_setup() will setup the call */
717 /* present to forwarded party */
718 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
719 e_callerinfo.present = INFO_PRESENT_ALLOWED;
723 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
724 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
725 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
726 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);
730 /* call to all internal interfaces */
731 p = e_ext.interfaces;
732 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
736 while(*p!=',' && *p!='\0')
741 /* search interface */
742 interface = hunt_interface(ifname);
744 trace_header("INTERFACE (not found)", DIRECTION_NONE);
745 add_trace("interface", NULL, "%s", ifname);
749 /* found interface */
750 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
751 if (interface->remote) {
754 if (admin->remote_name[0] && !strcmp(admin->remote_name, interface->remote_app))
759 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
760 add_trace("application", NULL, "%s", interface->remote_app);
764 SPRINT(portname, "%s-%d-out", interface->name, 0);
765 port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface, admin->sock);
766 earlyb = (interface->is_earlyb == IS_YES);
769 if (interface->gsm_bs) {
770 SPRINT(portname, "%s-%d-out", interface->name, 0);
771 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
772 earlyb = (interface->is_earlyb == IS_YES);
776 if (interface->gsm_ms) {
777 SPRINT(portname, "%s-%d-out", interface->name, 0);
778 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
779 earlyb = (interface->is_earlyb == IS_YES);
783 if (interface->sip) {
784 SPRINT(portname, "%s-%d-out", interface->name, 0);
785 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
786 earlyb = (interface->is_earlyb == IS_YES);
791 /* hunt for mISDNport and create Port */
792 mISDNport = hunt_port(ifname, &channel);
794 trace_header("INTERFACE (busy)", DIRECTION_NONE);
795 add_trace("interface", NULL, "%s", ifname);
800 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
803 port = ss5_hunt_line(mISDNport);
806 #ifdef ISDN_P_FXS_POTS
808 port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
811 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, channel, mISDNport->ifport->channel_force, mode);
812 earlyb = mISDNport->earlyb;
814 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
815 add_trace("interface", NULL, "%s", ifname);
821 FATAL("Failed to create Port instance\n");
822 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
823 memset(&dialinginfo, 0, sizeof(dialinginfo));
824 SCPY(dialinginfo.id, e_dialinginfo.id);
825 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
826 dialinginfo.ntype = e_dialinginfo.ntype;
827 /* create port_list relation */
828 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
830 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
832 goto check_anycall_intern;
835 if (e_callerinfo.id[0] && e_ext.display_name) {
836 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
838 SCPY(e_callerinfo.name, dirname);
840 // dss1 = (class Pdss1 *)port;
842 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
843 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
844 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
845 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
846 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
847 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
848 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
849 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
850 //terminal if (e_dialinginfo.id)
851 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
852 /* handle restricted caller ids */
853 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);
854 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);
855 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);
856 /* display callerid if desired for extension */
857 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));
858 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
859 /* use cnip, if enabld */
860 // if (!e_ext.centrex)
861 // message->param.setup.callerinfo.name[0] = '\0';
862 /* screen clip if prefix is required */
863 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
864 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
865 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
866 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
868 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
869 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
870 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
871 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
873 /* use internal caller id */
874 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
875 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
876 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
877 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
879 message_put(message);
880 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
884 /* string from parallel call forward (cfp) */
887 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
888 e_callerinfo.present = INFO_PRESENT_ALLOWED;
889 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
893 vbox_only: /* entry point for answering machine only */
894 cfu_only: /* entry point for cfu */
895 cfb_only: /* entry point for cfb */
896 cfnr_only: /* entry point for cfnr */
897 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
901 /* only if vbox should be dialed, and terminal is given */
902 if (!strcmp(p, "vbox") && e_ext.number[0]) {
903 /* go to the end of p */
906 /* answering vbox call */
907 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
909 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
910 FATAL("No memory for VBOX Port instance\n");
911 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
912 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
915 while(*p!=',' && *p!='\0')
920 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
922 /* hunt for mISDNport and create Port */
923 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
925 /* creating EXTERNAL port*/
926 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
929 port = ss5_hunt_line(mISDNport);
932 #ifdef ISDN_P_FXS_POTS
934 port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
937 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, channel, mISDNport->ifport->channel_force, mode);
939 FATAL("No memory for Port instance\n");
940 earlyb = mISDNport->earlyb;
945 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
946 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
951 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
952 goto check_anycall_intern;
954 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
955 memset(&dialinginfo, 0, sizeof(dialinginfo));
956 SCPY(dialinginfo.id, cfp);
957 dialinginfo.itype = INFO_ITYPE_ISDN;
958 dialinginfo.ntype = e_dialinginfo.ntype;
959 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
961 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
963 goto check_anycall_intern;
965 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
966 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
967 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
968 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
969 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
970 /* if clip is hidden */
971 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
972 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
973 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
974 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
975 message->param.setup.callerinfo.present = e_ext.callerid_present;
976 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
978 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
979 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
980 //terminal if (e_dialinginfo.id)
981 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
982 /* handle restricted caller ids */
983 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);
984 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);
985 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);
986 /* display callerid if desired for extension */
987 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));
988 message_put(message);
989 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
993 check_anycall_intern:
994 /* now we have all ports created */
996 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
998 if (!ea_endpoint->ep_join_id)
1000 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1001 return; /* must exit here */
1005 /* *********************** external call */
1007 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1008 /* call to extenal interfaces */
1009 if (e_dialinginfo.keypad[0])
1010 number_p = e_dialinginfo.keypad;
1012 number_p = e_dialinginfo.id;
1015 while(*number_p!=',' && *number_p!='\0')
1016 SCCAT(number, *number_p++);
1017 if (*number_p == ',')
1021 ifname_p = e_dialinginfo.interfaces;
1022 if (*ifname_p == '+')
1027 while(*ifname_p!=',' && *ifname_p!='\0')
1028 SCCAT(ifname, *ifname_p++);
1029 if (*ifname_p == ',')
1031 /* found interface name */
1033 /* search interface */
1034 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, ifname[0]?ifname:"any interface");
1035 interface = hunt_interface(ifname[0]?ifname:NULL);
1037 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1038 add_trace("interface", NULL, "%s", ifname);
1042 /* found interface */
1043 if (interface->remote) {
1044 admin = admin_first;
1046 if (admin->remote_name[0] && !strcmp(admin->remote_name, interface->remote_app))
1048 admin = admin->next;
1051 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1052 add_trace("application", NULL, "%s", interface->remote_app);
1056 SPRINT(portname, "%s-%d-out", interface->name, 0);
1057 port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface, admin->sock);
1058 earlyb = (interface->is_earlyb == IS_YES);
1061 if (interface->gsm_bs) {
1062 SPRINT(portname, "%s-%d-out", interface->name, 0);
1063 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1064 earlyb = (interface->is_earlyb == IS_YES);
1068 if (interface->gsm_ms) {
1069 SPRINT(portname, "%s-%d-out", interface->name, 0);
1070 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1071 earlyb = (interface->is_earlyb == IS_YES);
1075 if (interface->sip) {
1076 SPRINT(portname, "%s-%d-out", interface->name, 0);
1077 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1078 earlyb = (interface->is_earlyb == IS_YES);
1083 /* hunt for mISDNport and create Port */
1084 mISDNport = hunt_port(ifname[0]?ifname:NULL, &channel);
1086 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1087 add_trace("interface", NULL, "%s", ifname[0]?ifname:"any interface");
1091 /* creating EXTERNAL port*/
1092 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1096 port = ss5_hunt_line(mISDNport);
1099 #ifdef ISDN_P_FXS_POTS
1100 if (mISDNport->pots)
1101 port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
1104 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, channel, mISDNport->ifport->channel_force, mode);
1105 earlyb = mISDNport->earlyb;
1107 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
1108 add_trace("interface", NULL, "%s", ifname);
1114 FATAL("No memory for Port instance\n");
1115 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1116 memset(&dialinginfo, 0, sizeof(dialinginfo));
1117 if (e_dialinginfo.keypad[0])
1118 SCPY(dialinginfo.keypad, number);
1120 SCPY(dialinginfo.id, number);
1121 dialinginfo.itype = INFO_ITYPE_ISDN;
1122 dialinginfo.ntype = e_dialinginfo.ntype;
1123 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1124 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1126 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1130 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1131 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1132 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1133 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1134 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1135 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1136 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1137 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1138 //terminal if (e_dialinginfo.id)
1139 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1140 /* handle restricted caller ids */
1141 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);
1142 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);
1143 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);
1144 /* display callerid if desired for extension */
1145 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));
1146 message_put(message);
1147 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1150 /* found an interface
1151 * continue only if + is given, so every interface is calles parallel */
1152 if (e_dialinginfo.interfaces[0] != '+')
1154 } while (*ifname_p);
1157 /* now we have all ports created */
1159 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1161 if (!ea_endpoint->ep_join_id)
1163 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1164 return; /* must exit here */
1171 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1173 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1175 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1178 unsched_timer(&ea->e_redial_timeout);
1179 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1180 ea->e_multipoint_cause = 0;
1181 ea->e_multipoint_location = 0;
1182 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1183 ea->e_join_pattern = 0;
1184 ea->process_dialing(1);
1185 /* we must exit, because our endpoint might be gone */
1190 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1192 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1194 if (!ea->e_action) {
1195 unsched_timer(&ea->e_redial_timeout);
1196 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1197 ea->process_dialing(0);
1198 /* we must exit, because our endpoint might be gone */
1204 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1206 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1208 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1210 ea->new_state(EPOINT_STATE_OUT_SETUP);
1211 /* call special setup routine */
1217 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1219 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1221 /* leave power dialing on */
1222 ea->e_powerdial_on = 1;
1223 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1226 ea->e_ruleset = ruleset_main;
1228 ea->e_rule = ea->e_ruleset->rule_first;
1229 ea->e_action = NULL;
1230 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1231 ea->process_dialing(0);
1236 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1238 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1239 struct port_list *portlist;
1240 struct lcr_msg *message;
1242 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1244 /* release all ports */
1245 while((portlist = ea->ea_endpoint->ep_portlist)) {
1246 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1247 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1248 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1249 message_put(message);
1250 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1251 ea->ea_endpoint->free_portlist(portlist);
1254 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1255 message->param.audiopath = 0;
1256 message_put(message);
1257 /* indicate no patterns */
1258 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1259 message_put(message);
1260 /* set setup state, since we have no response from the new join */
1261 ea->new_state(EPOINT_STATE_OUT_SETUP);
1266 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1268 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1270 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);
1276 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1278 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1280 if (ea->e_state == EPOINT_STATE_IDLE) {
1281 /* epoint is idle, check callback */
1282 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1283 ea->new_state(EPOINT_STATE_OUT_SETUP);
1290 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1292 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1294 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1295 struct port_list *portlist;
1297 ea->e_ruleset = ruleset_main;
1299 ea->e_rule = ea->e_ruleset->rule_first;
1300 ea->e_action = NULL;
1301 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1302 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1304 ea->e_connectedmode = 0;
1306 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1307 portlist = ea->ea_endpoint->ep_portlist;
1309 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1310 ea->set_tone(portlist, "cause_10");
1317 /* doing a hookflash */
1318 void EndpointAppPBX::hookflash(void)
1323 /* be sure that we are active */
1325 e_tx_state = NOTIFY_STATE_ACTIVE;
1327 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1329 if (ea_endpoint->ep_use > 1) {
1330 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1333 /* dialtone after pressing the hash key */
1334 process_hangup(e_join_cause, e_join_location);
1335 e_multipoint_cause = 0;
1336 e_multipoint_location = 0;
1337 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1339 port->set_echotest(0);
1341 if (ea_endpoint->ep_join_id) {
1342 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1344 e_ruleset = ruleset_main;
1346 e_rule = e_ruleset->rule_first;
1348 new_state(EPOINT_STATE_IN_OVERLAP);
1349 e_connectedmode = 1;
1350 SCPY(e_dialinginfo.id, e_ext.prefix);
1351 e_extdialing = e_dialinginfo.id;
1353 if (e_dialinginfo.id[0]) {
1354 set_tone(ea_endpoint->ep_portlist, "dialing");
1357 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1365 /* messages from port
1367 /* port MESSAGE_SETUP */
1368 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1370 struct lcr_msg *message;
1372 int writeext; /* flags need to write extension after modification */
1375 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1377 portlist->port_type = param->setup.port_type;
1378 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1379 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1380 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1381 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1382 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
1384 /* convert (inter-)national number type */
1385 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1386 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1388 // e_dtmf = param->setup.dtmf;
1389 /* screen incoming caller id */
1390 if (e_callerinfo.interface[0]) {
1391 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface);
1392 if (e_callerinfo.id2[0]) do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
1393 if (e_redirinfo.id[0]) do_screen(0, e_redirinfo.id, sizeof(e_redirinfo.id), &e_redirinfo.ntype, &e_redirinfo.present, e_callerinfo.interface);
1396 /* process extension */
1397 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1398 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1399 /* port makes call from extension */
1400 SCPY(e_callerinfo.extension, e_callerinfo.id);
1401 SCPY(e_ext.number, e_callerinfo.extension);
1402 SCPY(e_extension_interface, e_callerinfo.interface);
1404 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1407 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1408 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1410 /* get extension's info about caller */
1411 if (!read_extension(&e_ext, e_ext.number)) {
1412 /* extension doesn't exist */
1413 trace_header("EXTENSION (not created)", DIRECTION_IN);
1414 add_trace("extension", NULL, "%s", e_ext.number);
1416 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1417 new_state(EPOINT_STATE_OUT_DISCONNECT);
1418 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1419 e_ext.number[0] = '\0'; /* no terminal */
1424 /* put prefix (next) in front of e_dialinginfo.id */
1425 if (e_ext.next[0]) {
1426 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1427 SCPY(e_dialinginfo.id, buffer);
1428 e_ext.next[0] = '\0';
1430 } else if (e_ext.prefix[0]) {
1431 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1432 SCPY(e_dialinginfo.id, buffer);
1435 /* screen caller id by extension's config */
1436 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1438 SCPY(e_callerinfo.name, e_ext.name);
1439 /* use caller id (or if exist: id_next_call) for this call */
1440 if (e_ext.id_next_call_present >= 0) {
1441 SCPY(e_callerinfo.id, e_ext.id_next_call);
1442 /* if we restrict the pesentation */
1443 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1444 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1445 else e_callerinfo.present = e_ext.id_next_call_present;
1446 e_callerinfo.ntype = e_ext.id_next_call_type;
1447 e_ext.id_next_call_present = -1;
1450 SCPY(e_callerinfo.id, e_ext.callerid);
1451 /* if we restrict the pesentation */
1452 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1453 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1454 else e_callerinfo.present = e_ext.callerid_present;
1455 e_callerinfo.ntype = e_ext.callerid_type;
1457 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1459 /* extension is written */
1461 write_extension(&e_ext, e_ext.number);
1463 /* set volume of rx and tx */
1464 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1465 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1466 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1467 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1468 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1469 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1470 message_put(message);
1473 /* start recording if enabled */
1474 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1475 /* check if we are a terminal */
1476 if (e_ext.number[0] == '\0')
1477 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1479 port = find_port_id(portlist->port_id);
1481 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1485 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1486 /* no terminal identification */
1487 e_ext.number[0] = '\0';
1488 e_extension_interface[0] = '\0';
1489 memset(&e_ext, 0, sizeof(e_ext));
1490 e_ext.rights = 4; /* right to dial internat */
1494 e_ruleset = ruleset_main;
1496 e_rule = e_ruleset->rule_first;
1498 e_extdialing = e_dialinginfo.id;
1499 new_state(EPOINT_STATE_IN_SETUP);
1500 if (e_dialinginfo.id[0]) {
1501 set_tone(portlist, "dialing");
1503 if (e_ext.number[0])
1504 set_tone(portlist, "dialpbx");
1506 set_tone(portlist, "dialtone");
1509 if (e_state == EPOINT_STATE_IN_SETUP) {
1510 /* request MORE info, if not already at higher state */
1511 new_state(EPOINT_STATE_IN_OVERLAP);
1512 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1513 message_put(message);
1514 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1518 /* port MESSAGE_INFORMATION */
1519 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1521 struct lcr_msg *message;
1523 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1525 /* ignore information message without digit information */
1526 if (!param->information.id[0])
1531 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1533 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1538 /* if vbox_play is done, the information are just used as they come */
1540 if (e_action->index == ACTION_VBOX_PLAY) {
1541 /* concat dialing string */
1542 SCAT(e_dialinginfo.id, param->information.id);
1547 /* keypad when disconnect but in connected mode */
1548 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1549 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1550 /* processing keypad function */
1551 if (param->information.id[0] == '0') {
1557 /* keypad when connected */
1558 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1559 if (e_enablekeypad) {
1560 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1561 memcpy(&message->param, param, sizeof(union parameter));
1562 message_put(message);
1566 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1567 /* processing keypad function */
1568 if (param->information.id[0] == '0') {
1571 if (param->information.id[0])
1572 keypad_function(param->information.id[0]);
1574 if (e_ext.number[0])
1575 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1577 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1582 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1583 if (e_ext.number[0])
1584 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1586 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1590 if (!param->information.id[0])
1592 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1593 set_tone(portlist, "dialing");
1596 if (e_action->index==ACTION_OUTDIAL
1597 || e_action->index==ACTION_EXTERNAL) {
1599 set_tone(portlist, "dialing");
1600 else if (!e_extdialing[0])
1601 set_tone(portlist, "dialing");
1603 /* concat dialing string */
1604 SCAT(e_dialinginfo.id, param->information.id);
1608 /* port MESSAGE_DTMF */
1609 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1612 struct lcr_msg *message;
1616 /* only if dtmf detection is enabled */
1618 trace_header("DTMF (disabled)", DIRECTION_IN);
1622 trace_header("DTMF", DIRECTION_IN);
1623 add_trace("digit", NULL, "%c", param->dtmf);
1627 NOTE: vbox is now handled due to overlap state
1628 /* if vbox_play is done, the dtmf digits are just used as they come */
1630 if (e_action->index == ACTION_VBOX_PLAY) {
1631 /* concat dialing string */
1632 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1633 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1634 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1637 /* continue to process *X# sequences */
1641 /* check for *X# sequence */
1642 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1643 if (e_enablekeypad) {
1644 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1645 memcpy(&message->param, param, sizeof(union parameter));
1646 message_put(message);
1649 if (e_dtmf_time+3 < now) {
1650 /* the last digit was too far in the past to be a sequence */
1651 if (param->dtmf == '*')
1652 /* only start is allowed in the sequence */
1657 /* we have a sequence of digits, see what we got */
1658 if (param->dtmf == '*')
1660 else if (param->dtmf>='0' && param->dtmf<='9') {
1661 /* we need to have a star before we receive the digit of the sequence */
1662 if (e_dtmf_last == '*')
1663 e_dtmf_last = param->dtmf;
1664 } else if (param->dtmf == '#') {
1666 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1667 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1668 if (e_dtmf_last == '0') {
1672 /* processing keypad function */
1674 keypad_function(e_dtmf_last);
1680 /* set last time of dtmf */
1685 /* check for ## hookflash during dialing */
1687 if (e_action->index==ACTION_PASSWORD
1688 || e_action->index==ACTION_PASSWORD_WRITE)
1690 if (param->dtmf=='#') { /* current digit is '#' */
1691 if (e_state==EPOINT_STATE_IN_DISCONNECT
1692 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1706 /* dialing using dtmf digit */
1707 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1708 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1709 set_tone(portlist, "dialing");
1711 /* concat dialing string */
1712 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1713 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1714 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1720 /* port MESSAGE_CRYPT */
1721 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1724 /* send crypt response to cryptman */
1725 if (param->crypt.type == CR_MESSAGE_IND)
1726 cryptman_msg2man(param->crypt.data, param->crypt.len);
1728 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1732 /* port MESSAGE_OVERLAP */
1733 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1735 struct lcr_msg *message;
1737 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1739 /* signal to call tool */
1740 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1742 if (e_dialing_queue[0] && portlist) {
1743 /* send what we have not dialed yet, because we had no setup complete */
1744 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1745 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1746 SCPY(message->param.information.id, e_dialing_queue);
1747 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1748 message_put(message);
1749 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1750 e_dialing_queue[0] = '\0';
1752 /* check if pattern is available */
1753 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1754 /* indicate patterns */
1755 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1756 message_put(message);
1758 /* connect audio, if not already */
1759 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1760 message->param.audiopath = 1;
1761 message_put(message);
1763 /* indicate no patterns */
1764 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1765 message_put(message);
1767 /* disconnect audio, if not already */
1768 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1769 message->param.audiopath = 0;
1770 message_put(message);
1772 new_state(EPOINT_STATE_OUT_OVERLAP);
1773 /* if we are in a join */
1774 if (ea_endpoint->ep_join_id) {
1775 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1776 memcpy(&message->param, param, sizeof(union parameter));
1777 message_put(message);
1781 /* port MESSAGE_PROCEEDING */
1782 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1784 struct lcr_msg *message;
1786 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1788 /* signal to call tool */
1789 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1791 e_state = EPOINT_STATE_OUT_PROCEEDING;
1792 /* check if pattern is availatle */
1793 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1794 /* indicate patterns */
1795 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1796 message_put(message);
1798 /* connect audio, if not already */
1799 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1800 message->param.audiopath = 1;
1801 message_put(message);
1803 /* indicate no patterns */
1804 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1805 message_put(message);
1807 /* disconnect audio, if not already */
1808 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1809 message->param.audiopath = 0;
1810 message_put(message);
1812 /* if we are in a call */
1813 if (ea_endpoint->ep_join_id) {
1814 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1815 memcpy(&message->param, param, sizeof(union parameter));
1816 message_put(message);
1820 /* port MESSAGE_ALERTING */
1821 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1823 struct lcr_msg *message;
1825 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1827 /* signal to call tool */
1828 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1831 // set_tone(portlist, "hold");
1833 new_state(EPOINT_STATE_OUT_ALERTING);
1834 /* check if pattern is available */
1835 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1836 /* indicate patterns */
1837 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1838 message_put(message);
1840 /* connect audio, if not already */
1841 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1842 message->param.audiopath = 1;
1843 message_put(message);
1845 /* indicate no patterns */
1846 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1847 message_put(message);
1849 /* disconnect audio, if not already */
1850 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1851 message->param.audiopath = 0;
1852 message_put(message);
1854 /* if we are in a call */
1855 if (ea_endpoint->ep_join_id) {
1856 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1857 memcpy(&message->param, param, sizeof(union parameter));
1858 message_put(message);
1862 /* port MESSAGE_CONNECT */
1863 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1865 struct lcr_msg *message;
1867 unsigned int port_id = portlist->port_id;
1868 struct port_list *tportlist;
1872 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1874 /* signal to call tool */
1875 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1877 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1878 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1879 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1880 tportlist = ea_endpoint->ep_portlist;
1881 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1882 tportlist = tportlist->next;
1883 if (tportlist->port_id == port_id)
1884 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1885 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1886 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1887 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1888 message_put(message);
1889 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1890 ea_endpoint->free_portlist(tportlist);
1892 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1897 if (e_callerinfo.interface[0])
1898 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface);
1900 /* screen connected name */
1902 SCPY(e_connectinfo.name, e_ext.name);
1904 /* add internal id to colp */
1905 SCPY(e_connectinfo.extension, e_ext.number);
1907 /* we store the connected port number */
1908 SCPY(e_extension_interface, e_connectinfo.interface);
1910 /* for internal and am calls, we get the extension's id */
1911 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1912 SCPY(e_connectinfo.id, e_ext.callerid);
1913 SCPY(e_connectinfo.extension, e_ext.number);
1914 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1915 e_connectinfo.ntype = e_ext.callerid_type;
1916 e_connectinfo.present = e_ext.callerid_present;
1918 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
1919 e_connectinfo.itype = INFO_ITYPE_VBOX;
1920 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1923 new_state(EPOINT_STATE_CONNECT);
1925 /* set volume of rx and tx */
1926 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1927 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1928 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1929 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1930 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1931 message_put(message);
1934 unsched_timer(&e_cfnr_timeout);
1935 unsched_timer(&e_cfnr_call_timeout);
1936 if (e_ext.number[0])
1937 e_dtmf = 1; /* allow dtmf */
1940 /* other calls with no caller id (or not available for the extension) and force colp */
1941 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
1942 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
1943 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
1944 /* external extension answered */
1945 port = find_port_id(portlist->port_id);
1947 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
1948 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1953 /* send connect to join */
1954 if (ea_endpoint->ep_join_id) {
1955 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1956 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1957 message_put(message);
1959 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1960 message->param.audiopath = 1;
1961 message_put(message);
1962 } else if (!e_adminid) {
1964 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
1965 SCPY(e_ext.number, e_cbcaller);
1966 new_state(EPOINT_STATE_IN_OVERLAP);
1967 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1969 /* get extension's info about terminal */
1970 if (!read_extension(&e_ext, e_ext.number)) {
1971 /* extension doesn't exist */
1972 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1973 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1974 new_state(EPOINT_STATE_OUT_DISCONNECT);
1975 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1979 /* put prefix in front of e_cbdialing */
1980 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
1981 SCPY(e_dialinginfo.id, buffer);
1982 e_dialinginfo.itype = INFO_ITYPE_ISDN;
1983 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1985 /* use caller id (or if exist: id_next_call) for this call */
1986 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1987 SCPY(e_callerinfo.extension, e_ext.number);
1988 if (e_ext.id_next_call_present >= 0) {
1989 SCPY(e_callerinfo.id, e_ext.id_next_call);
1990 e_callerinfo.present = e_ext.id_next_call_present;
1991 e_callerinfo.ntype = e_ext.id_next_call_type;
1992 e_ext.id_next_call_present = -1;
1993 /* extension is written */
1994 write_extension(&e_ext, e_ext.number);
1996 SCPY(e_callerinfo.id, e_ext.callerid);
1997 e_callerinfo.present = e_ext.callerid_present;
1998 e_callerinfo.ntype = e_ext.callerid_type;
2000 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2002 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2005 /* check if caller id is NOT authenticated */
2006 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2007 /* make call state to enter password */
2008 new_state(EPOINT_STATE_IN_OVERLAP);
2009 e_action = &action_password_write;
2010 unsched_timer(&e_match_timeout);
2011 e_match_to_action = NULL;
2012 e_dialinginfo.id[0] = '\0';
2013 e_extdialing = strchr(e_dialinginfo.id, '\0');
2014 schedule_timer(&e_password_timeout, 20, 0);
2017 /* incoming call (callback) */
2018 e_ruleset = ruleset_main;
2020 e_rule = e_ruleset->rule_first;
2022 e_extdialing = e_dialinginfo.id;
2023 if (e_dialinginfo.id[0]) {
2024 set_tone(portlist, "dialing");
2027 set_tone(portlist, "dialpbx");
2030 } else { /* testcall */
2031 set_tone(portlist, "hold");
2034 /* start recording if enabled, not when answering machine answers */
2035 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)) {
2036 /* check if we are a terminal */
2037 if (e_ext.number[0] == '\0')
2038 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2040 port = find_port_id(portlist->port_id);
2042 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2047 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2048 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2050 struct lcr_msg *message;
2052 unsigned int port_id = portlist->port_id;
2056 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2058 /* signal to call tool */
2059 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2061 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2062 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2063 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2068 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);
2069 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2070 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2072 /* check if we have more than one portlist relation and we just ignore the disconnect */
2073 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2074 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2075 portlist = ea_endpoint->ep_portlist;
2077 if (portlist->port_id == port_id)
2079 portlist = portlist->next;
2082 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2083 if (message_type != MESSAGE_RELEASE) {
2084 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2085 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2086 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2087 message_put(message);
2088 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2090 ea_endpoint->free_portlist(portlist);
2091 return; /* one relation removed */
2093 if (e_state == EPOINT_STATE_CONNECT) {
2094 /* use cause from port after connect */
2095 cause = param->disconnectinfo.cause;
2096 location = param->disconnectinfo.location;
2098 /* use multipoint cause if no connect yet */
2099 if (e_multipoint_cause) {
2100 cause = e_multipoint_cause;
2101 location = e_multipoint_location;
2103 cause = CAUSE_NOUSER;
2104 location = LOCATION_PRIVATE_LOCAL;
2108 unsched_timer(&e_cfnr_timeout);
2109 unsched_timer(&e_cfnr_call_timeout);
2111 /* process hangup */
2112 process_hangup(e_join_cause, e_join_location);
2113 e_multipoint_cause = 0;
2114 e_multipoint_location = 0;
2116 if (message_type == MESSAGE_DISCONNECT) {
2117 /* tone to disconnected end */
2118 SPRINT(buffer, "cause_%02x", cause);
2119 if (ea_endpoint->ep_portlist)
2120 set_tone(ea_endpoint->ep_portlist, buffer);
2122 new_state(EPOINT_STATE_IN_DISCONNECT);
2125 if (ea_endpoint->ep_join_id) {
2126 int haspatterns = 0;
2127 /* check if pattern is available */
2128 if (ea_endpoint->ep_portlist)
2129 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2130 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
2131 && message_type != MESSAGE_RELEASE) // if we release, we are done
2134 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2135 /* indicate patterns */
2136 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2137 message_put(message);
2138 /* connect audio, if not already */
2139 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2140 message->param.audiopath = 1;
2141 message_put(message);
2142 /* send disconnect */
2143 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2144 memcpy(&message->param, param, sizeof(union parameter));
2145 message_put(message);
2146 /* disable encryption if disconnected */
2147 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2150 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2154 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2157 if (message_type == MESSAGE_RELEASE)
2158 ea_endpoint->free_portlist(portlist);
2159 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2160 return; /* must exit here */
2163 /* port MESSAGE_TIMEOUT */
2164 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2168 trace_header("TIMEOUT", DIRECTION_IN);
2169 message_type = MESSAGE_DISCONNECT;
2170 switch (param->state) {
2171 case PORT_STATE_OUT_SETUP:
2172 case PORT_STATE_OUT_OVERLAP:
2173 add_trace("state", NULL, "outgoing setup/dialing");
2175 /* no user responding */
2176 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2177 return; /* must exit here */
2179 case PORT_STATE_IN_SETUP:
2180 case PORT_STATE_IN_OVERLAP:
2181 add_trace("state", NULL, "incoming setup/dialing");
2182 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2183 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2186 case PORT_STATE_OUT_PROCEEDING:
2187 add_trace("state", NULL, "outgoing proceeding");
2189 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2190 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2191 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2192 return; /* must exit here */
2194 case PORT_STATE_IN_PROCEEDING:
2195 add_trace("state", NULL, "incoming proceeding");
2196 param->disconnectinfo.cause = CAUSE_NOUSER;
2197 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2200 case PORT_STATE_OUT_ALERTING:
2201 add_trace("state", NULL, "outgoing alerting");
2203 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2204 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2205 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2206 return; /* must exit here */
2208 case PORT_STATE_CONNECT:
2209 add_trace("state", NULL, "connect");
2211 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2212 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2213 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2214 return; /* must exit here */
2216 case PORT_STATE_IN_ALERTING:
2217 add_trace("state", NULL, "incoming alerting");
2218 param->disconnectinfo.cause = CAUSE_NOANSWER;
2219 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2222 case PORT_STATE_IN_DISCONNECT:
2223 case PORT_STATE_OUT_DISCONNECT:
2224 add_trace("state", NULL, "disconnect");
2226 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2227 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2228 return; /* must exit here */
2231 param->disconnectinfo.cause = 31; /* normal unspecified */
2232 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2235 /* release call, disconnect isdn */
2237 new_state(EPOINT_STATE_OUT_DISCONNECT);
2238 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2239 SCPY(e_tone, cause);
2241 set_tone(portlist, cause);
2242 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2243 portlist = portlist->next;
2245 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2248 /* port MESSAGE_NOTIFY */
2249 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2251 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2253 struct lcr_msg *message;
2255 /* signal to call tool */
2256 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);
2257 if (param->notifyinfo.notify) {
2258 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2261 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2262 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2263 case INFO_NOTIFY_REMOTE_HOLD:
2264 case INFO_NOTIFY_USER_SUSPENDED:
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 = 0;
2269 message_put(message);
2273 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2274 case INFO_NOTIFY_USER_RESUMED:
2275 /* set volume of rx and tx */
2276 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2277 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2279 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2280 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2281 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2282 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2283 message_put(message);
2285 /* set current tone */
2287 set_tone(portlist, e_tone);
2288 /* tell call about it */
2289 if (ea_endpoint->ep_join_id) {
2290 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2291 message->param.audiopath = 1;
2292 message_put(message);
2297 /* notify call if available */
2298 if (ea_endpoint->ep_join_id) {
2299 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2300 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2301 message_put(message);
2306 /* port MESSAGE_PROGRESS */
2307 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2309 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2311 struct lcr_msg *message;
2313 /* signal to call tool */
2314 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2316 /* send progress to call if available */
2317 if (ea_endpoint->ep_join_id) {
2318 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2319 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2320 message_put(message);
2325 /* port MESSAGE_FACILITY */
2326 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2328 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2330 struct lcr_msg *message;
2332 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2333 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2334 message_put(message);
2337 /* port MESSAGE_3PTY */
2338 void EndpointAppPBX::port_3pty(struct port_list *portlist, int message_type, union parameter *param)
2340 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2342 struct lcr_msg *message;
2346 if (param->threepty.begin)
2347 rc = join_3pty_dss1();
2348 else if (param->threepty.end)
2353 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_3PTY);
2354 message->param.threepty.begin = param->threepty.begin;
2355 message->param.threepty.end = param->threepty.end;
2357 message->param.threepty.error = 1;
2359 message->param.threepty.result = 1;
2360 message->param.threepty.invoke_id = param->threepty.invoke_id;
2361 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2362 message_put(message);
2365 /* port MESSAGE_TRANSFER */
2366 void EndpointAppPBX::port_transfer(struct port_list *portlist, int message_type, union parameter *param)
2368 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2372 /* bridge for real */
2373 if (!(port = find_port_id(portlist->port_id)))
2375 if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS)
2377 else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1)
2381 /* port MESSAGE_SUSPEND */
2382 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2383 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2385 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2387 /* epoint is now parked */
2388 ea_endpoint->ep_park = 1;
2389 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2390 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2392 /* remove port relation */
2393 ea_endpoint->free_portlist(portlist);
2396 /* port MESSAGE_RESUME */
2397 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2398 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2400 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2402 /* epoint is now resumed */
2403 ea_endpoint->ep_park = 0;
2407 /* port MESSAGE_ENABLEKEYPAD */
2408 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2410 struct lcr_msg *message;
2412 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2414 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2415 memcpy(&message->param, param, sizeof(union parameter));
2416 message_put(message);
2420 /* port MESSAGE_DISABLE_DEJITTER */
2421 void EndpointAppPBX::port_disable_dejitter(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_DISABLE_DEJITTER);
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);
2497 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming 3PTY facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2498 port_3pty(portlist, message_type, param);
2501 case MESSAGE_TRANSFER:
2502 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming TRANSFER request (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2503 port_transfer(portlist, message_type, param);
2506 /* PORT sends DTMF message */
2507 case MESSAGE_DTMF: /* dtmf digits received */
2508 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);
2509 port_dtmf(portlist, message_type, param);
2512 /* PORT sends CRYPT message */
2513 case MESSAGE_CRYPT: /* crypt response received */
2514 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2515 port_crypt(portlist, message_type, param);
2518 /* PORT sends MORE message */
2519 case MESSAGE_OVERLAP:
2520 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);
2521 if (e_state != EPOINT_STATE_OUT_SETUP) {
2522 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);
2525 port_overlap(portlist, message_type, param);
2528 /* PORT sends PROCEEDING message */
2529 case MESSAGE_PROCEEDING: /* port is proceeding */
2530 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);
2531 if (e_state!=EPOINT_STATE_OUT_SETUP
2532 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2533 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);
2536 port_proceeding(portlist, message_type, param);
2539 /* PORT sends ALERTING message */
2540 case MESSAGE_ALERTING:
2541 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);
2542 if (e_state!=EPOINT_STATE_OUT_SETUP
2543 && e_state!=EPOINT_STATE_OUT_OVERLAP
2544 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2545 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);
2548 port_alerting(portlist, message_type, param);
2551 /* PORT sends CONNECT message */
2552 case MESSAGE_CONNECT:
2553 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);
2554 if (e_state!=EPOINT_STATE_OUT_SETUP
2555 && e_state!=EPOINT_STATE_OUT_OVERLAP
2556 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2557 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2558 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2561 port_connect(portlist, message_type, param);
2564 /* PORT sends DISCONNECT message */
2565 case MESSAGE_DISCONNECT: /* port is disconnected */
2566 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);
2567 port_disconnect_release(portlist, message_type, param);
2570 /* PORT sends a RELEASE message */
2571 case MESSAGE_RELEASE: /* port releases */
2572 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);
2573 /* portlist is release at port_disconnect_release, thanx Paul */
2574 port_disconnect_release(portlist, message_type, param);
2577 /* PORT sends a TIMEOUT message */
2578 case MESSAGE_TIMEOUT:
2579 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);
2580 port_timeout(portlist, message_type, param);
2581 break; /* release */
2583 /* PORT sends a NOTIFY message */
2584 case MESSAGE_NOTIFY:
2585 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);
2586 port_notify(portlist, message_type, param);
2589 /* PORT sends a PROGRESS message */
2590 case MESSAGE_PROGRESS:
2591 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);
2592 port_progress(portlist, message_type, param);
2595 /* PORT sends a SUSPEND message */
2596 case MESSAGE_SUSPEND:
2597 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);
2598 port_suspend(portlist, message_type, param);
2599 break; /* suspend */
2601 /* PORT sends a RESUME message */
2602 case MESSAGE_RESUME:
2603 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);
2604 port_resume(portlist, message_type, param);
2608 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2609 /* port assigns bchannel */
2610 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2611 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);
2612 /* only one port is expected to be connected to bchannel */
2613 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2614 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2618 /* PORT requests DTMF */
2619 case MESSAGE_ENABLEKEYPAD:
2620 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);
2621 port_enablekeypad(portlist, message_type, param);
2624 case MESSAGE_DISABLE_DEJITTER:
2625 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming disable dejitter message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2626 port_disable_dejitter(portlist, message_type, param);
2631 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);
2634 /* Note: this endpoint may be destroyed, so we MUST return */
2638 /* messages from join
2640 /* join MESSAGE_CRYPT */
2641 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2644 switch(param->crypt.type) {
2645 /* message from remote port to "crypt manager" */
2646 case CU_ACTK_REQ: /* activate key-exchange */
2647 case CU_ACTS_REQ: /* activate shared key */
2648 case CU_DACT_REQ: /* deactivate */
2649 case CU_INFO_REQ: /* request last info message */
2650 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2653 /* message from "crypt manager" to user */
2654 case CU_ACTK_CONF: /* key-echange done */
2655 case CU_ACTS_CONF: /* shared key done */
2656 case CU_DACT_CONF: /* deactivated */
2657 case CU_DACT_IND: /* deactivated */
2658 case CU_ERROR_IND: /* receive error message */
2659 case CU_INFO_IND: /* receive info message */
2660 case CU_INFO_CONF: /* receive info message */
2661 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2665 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);
2670 /* join MESSAGE_INFORMATION */
2671 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2673 struct lcr_msg *message;
2678 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2679 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2680 message_put(message);
2681 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2682 portlist = portlist->next;
2686 /* join MESSAGE_FACILITY */
2687 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2689 struct lcr_msg *message;
2691 if (!e_ext.facility && e_ext.number[0]) {
2696 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2697 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2698 message_put(message);
2699 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2700 portlist = portlist->next;
2704 /* join MESSAGE_MORE */
2705 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2707 struct lcr_msg *message;
2709 new_state(EPOINT_STATE_IN_OVERLAP);
2712 if (e_join_pattern && e_ext.own_setup) {
2713 /* disconnect audio */
2714 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2715 message->param.audiopath = 0;
2716 message_put(message);
2718 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2719 if (e_dialinginfo.id[0])
2720 set_tone(portlist, "dialing");
2722 set_tone(portlist, "dialtone");
2725 if (e_dialinginfo.id[0]) {
2726 set_tone(portlist, "dialing");
2728 if (e_ext.number[0])
2729 set_tone(portlist, "dialpbx");
2731 set_tone(portlist, "dialtone");
2735 /* join MESSAGE_PROCEEDING */
2736 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2738 struct lcr_msg *message;
2740 new_state(EPOINT_STATE_IN_PROCEEDING);
2742 /* own proceeding tone */
2743 if (e_join_pattern) {
2744 /* connect / disconnect audio */
2745 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2746 if (e_ext.own_proceeding)
2747 message->param.audiopath = 0;
2749 message->param.audiopath = 1;
2750 message_put(message);
2752 // UCPY(e_join_tone, "proceeding");
2754 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2755 message_put(message);
2756 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2758 set_tone(portlist, "proceeding");
2761 /* join MESSAGE_ALERTING */
2762 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2764 struct lcr_msg *message;
2766 new_state(EPOINT_STATE_IN_ALERTING);
2768 /* own alerting tone */
2769 if (e_join_pattern) {
2770 /* connect / disconnect audio */
2771 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2772 if (e_ext.own_alerting)
2773 message->param.audiopath = 0;
2775 message->param.audiopath = 1;
2776 message_put(message);
2779 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2780 message_put(message);
2781 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2783 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2784 set_tone(portlist, "ringing");
2787 if (e_ext.number[0])
2788 set_tone(portlist, "ringpbx");
2790 set_tone(portlist, "ringing");
2792 if (e_ext.number[0])
2793 e_dtmf = 1; /* allow dtmf */
2796 /* join MESSAGE_CONNECT */
2797 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2799 struct lcr_msg *message;
2802 new_state(EPOINT_STATE_CONNECT);
2803 // UCPY(e_join_tone, "");
2805 if (e_ext.number[0])
2806 e_dtmf = 1; /* allow dtmf */
2809 unsched_timer(&e_powerdial_timeout);
2810 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2812 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2813 memcpy(&message->param, param, sizeof(union parameter));
2815 /* screen clip if prefix is required */
2816 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2817 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2818 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2819 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2822 /* use internal caller id */
2823 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2824 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2825 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2828 /* handle restricted caller ids */
2829 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);
2830 /* display callerid if desired for extension */
2831 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));
2833 /* use conp, if enabld */
2834 // if (!e_ext.centrex)
2835 // message->param.connectinfo.name[0] = '\0';
2838 message_put(message);
2839 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2841 set_tone(portlist, NULL);
2843 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2844 message->param.audiopath = 1;
2845 message_put(message);
2850 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2851 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2854 struct lcr_msg *message;
2855 struct port_list *portlist = NULL;
2859 /* be sure that we are active */
2861 e_tx_state = NOTIFY_STATE_ACTIVE;
2863 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2864 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2865 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2867 /* set time for power dialing */
2868 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2871 /* set redial tone */
2872 if (ea_endpoint->ep_portlist) {
2875 set_tone(ea_endpoint->ep_portlist, "redial");
2876 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);
2877 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2878 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2879 new_state(EPOINT_STATE_IN_PROCEEDING);
2880 if (ea_endpoint->ep_portlist) {
2881 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2882 message_put(message);
2883 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2885 /* caused the error, that the first knock sound was not there */
2886 /* set_tone(portlist, "proceeding"); */
2888 /* send display of powerdialing */
2889 if (e_ext.display_dialing) {
2890 portlist = ea_endpoint->ep_portlist;
2892 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2894 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2896 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2897 message_put(message);
2898 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2899 portlist = portlist->next;
2909 if ((e_state!=EPOINT_STATE_CONNECT
2910 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2911 && e_state!=EPOINT_STATE_IN_OVERLAP
2912 && e_state!=EPOINT_STATE_IN_PROCEEDING
2913 && e_state!=EPOINT_STATE_IN_ALERTING)
2914 || !ea_endpoint->ep_portlist) { /* or no port */
2915 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2916 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2917 return; /* must exit here */
2920 if (!e_join_cause) {
2921 e_join_cause = param->disconnectinfo.cause;
2922 e_join_location = param->disconnectinfo.location;
2925 /* on release we need the audio again! */
2926 if (message_type == MESSAGE_RELEASE) {
2928 ea_endpoint->ep_join_id = 0;
2930 /* disconnect and select tone */
2931 new_state(EPOINT_STATE_OUT_DISCONNECT);
2932 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2933 /* if own_cause, we must release the join */
2934 if (e_ext.own_cause /* own cause */
2935 || !e_join_pattern) { /* no patterns */
2936 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);
2937 if (message_type != MESSAGE_RELEASE)
2938 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2940 } else { /* else we enable audio */
2941 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2942 message->param.audiopath = 1;
2943 message_put(message);
2945 /* send disconnect message */
2946 SCPY(e_tone, cause);
2947 portlist = ea_endpoint->ep_portlist;
2949 set_tone(portlist, cause);
2950 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2951 portlist = portlist->next;
2955 /* join MESSAGE_SETUP */
2956 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2958 struct lcr_msg *message;
2959 // struct interface *interface;
2961 /* if we already in setup state, we just update the dialing with new digits */
2962 if (e_state == EPOINT_STATE_OUT_SETUP
2963 || e_state == EPOINT_STATE_OUT_OVERLAP) {
2964 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
2965 /* if digits changed, what we have already dialed */
2966 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
2967 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);
2968 /* release all ports */
2969 while((portlist = ea_endpoint->ep_portlist)) {
2970 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2971 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2972 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2973 message_put(message);
2974 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2975 ea_endpoint->free_portlist(portlist);
2978 /* disconnect audio */
2979 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2980 message->param.audiopath = 0;
2981 message_put(message);
2983 /* get dialing info */
2984 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
2985 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2986 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
2987 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
2988 new_state(EPOINT_STATE_OUT_OVERLAP);
2991 schedule_timer(&e_redial_timeout, 1, 0);
2994 /* if we have a pending redial, so we just adjust the dialing number */
2995 if (e_redial_timeout.active) {
2996 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);
2997 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3000 if (!ea_endpoint->ep_portlist) {
3001 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3003 if (ea_endpoint->ep_portlist->next) {
3004 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3006 if (e_state == EPOINT_STATE_OUT_SETUP) {
3008 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);
3009 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3012 /* get what we have not dialed yet */
3013 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));
3014 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3015 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3016 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3017 message_put(message);
3018 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3020 /* always store what we have dialed or queued */
3021 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3025 if (e_state != EPOINT_STATE_IDLE) {
3026 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3029 /* if an internal extension is dialed, copy that number */
3030 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3031 SCPY(e_ext.number, param->setup.dialinginfo.id);
3032 /* if an internal extension is dialed, get extension's info about caller */
3033 if (e_ext.number[0]) {
3034 if (!read_extension(&e_ext, e_ext.number)) {
3035 e_ext.number[0] = '\0';
3036 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3040 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3041 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3042 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3043 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3044 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3046 /* process (voice over) data calls */
3047 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3048 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3049 memset(&e_capainfo, 0, sizeof(e_capainfo));
3050 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3051 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3052 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3055 new_state(EPOINT_STATE_OUT_SETUP);
3056 /* call special setup routine */
3060 /* join MESSAGE_mISDNSIGNAL */
3061 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3063 struct lcr_msg *message;
3066 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3067 memcpy(&message->param, param, sizeof(union parameter));
3068 message_put(message);
3069 portlist = portlist->next;
3073 /* join MESSAGE_BRIDE */
3074 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3076 struct lcr_msg *message;
3079 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3080 memcpy(&message->param, param, sizeof(union parameter));
3081 message_put(message);
3082 portlist = portlist->next;
3086 /* join MESSAGE_NOTIFY */
3087 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3089 struct lcr_msg *message;
3092 if (param->notifyinfo.notify) {
3093 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3094 // /* if notification was generated locally, we turn hold music on/off */
3095 // if (param->notifyinfo.local)
3096 // 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)
3100 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3101 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3103 set_tone(portlist, "");
3104 portlist = portlist->next;
3107 portlist = ea_endpoint->ep_portlist;
3112 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3114 set_tone(portlist, "hold");
3115 portlist = portlist->next;
3117 portlist = ea_endpoint->ep_portlist;
3122 /* save new state */
3123 e_tx_state = new_state;
3126 /* notify port(s) about it */
3128 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3129 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3130 /* handle restricted caller ids */
3131 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3132 /* display callerid if desired for extension */
3133 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));
3134 message_put(message);
3135 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3136 portlist = portlist->next;
3140 /* join MESSAGE_DTMF */
3141 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3143 struct lcr_msg *message;
3146 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3147 memcpy(&message->param, param, sizeof(union parameter));
3148 message_put(message);
3149 portlist = portlist->next;
3153 /* join MESSAGE_DISABLE_DEJITTER */
3154 void EndpointAppPBX::join_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
3156 struct lcr_msg *message;
3159 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISABLE_DEJITTER);
3160 memcpy(&message->param, param, sizeof(union parameter));
3161 message_put(message);
3162 portlist = portlist->next;
3166 /* JOIN sends messages to the endpoint
3168 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3170 struct port_list *portlist;
3171 struct lcr_msg *message;
3174 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3178 portlist = ea_endpoint->ep_portlist;
3180 // 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);
3181 switch(message_type) {
3182 /* JOIN SENDS TONE message */
3184 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);
3185 set_tone(portlist, param->tone.name);
3188 /* JOIN SENDS CRYPT message */
3190 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);
3191 join_crypt(portlist, message_type, param);
3194 /* JOIN sends INFORMATION message */
3195 case MESSAGE_INFORMATION:
3196 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);
3197 join_information(portlist, message_type, param);
3200 /* JOIN sends FACILITY message */
3201 case MESSAGE_FACILITY:
3202 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);
3203 join_facility(portlist, message_type, param);
3206 /* JOIN sends OVERLAP message */
3207 case MESSAGE_OVERLAP:
3208 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);
3209 if (e_state!=EPOINT_STATE_IN_SETUP
3210 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3211 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3214 join_overlap(portlist, message_type, param);
3217 /* JOIN sends PROCEEDING message */
3218 case MESSAGE_PROCEEDING:
3219 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);
3220 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3221 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3224 join_proceeding(portlist, message_type, param);
3227 /* JOIN sends ALERTING message */
3228 case MESSAGE_ALERTING:
3229 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);
3230 if (e_state!=EPOINT_STATE_IN_OVERLAP
3231 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3232 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3235 join_alerting(portlist, message_type, param);
3238 /* JOIN sends CONNECT message */
3239 case MESSAGE_CONNECT:
3240 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);
3241 if (e_state!=EPOINT_STATE_IN_OVERLAP
3242 && e_state!=EPOINT_STATE_IN_PROCEEDING
3243 && e_state!=EPOINT_STATE_IN_ALERTING) {
3244 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3247 join_connect(portlist, message_type, param);
3250 /* JOIN sends DISCONNECT/RELEASE message */
3251 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3252 case MESSAGE_RELEASE: /* JOIN releases */
3253 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);
3254 join_disconnect_release(message_type, param);
3257 /* JOIN sends SETUP message */
3259 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);
3260 join_setup(portlist, message_type, param);
3263 /* JOIN sends special mISDNSIGNAL message */
3264 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3265 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);
3266 join_mISDNsignal(portlist, message_type, param);
3269 /* JOIN sends bridge message */
3270 case MESSAGE_BRIDGE: /* bride message to port */
3271 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);
3272 join_bridge(portlist, message_type, param);
3275 /* JOIN has pattern available */
3276 case MESSAGE_PATTERN: /* indicating pattern available */
3277 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);
3278 if (!e_join_pattern) {
3279 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3283 set_tone(portlist, NULL);
3284 portlist = portlist->next;
3286 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3287 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3288 message->param.audiopath = 1;
3289 message_put(message);
3293 /* JOIN has no pattern available */
3294 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3295 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);
3296 if (e_join_pattern) {
3297 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3299 /* disconnect our audio tx and rx */
3300 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3301 message->param.audiopath = 0;
3302 message_put(message);
3307 /* JOIN (dunno at the moment) */
3308 case MESSAGE_REMOTE_AUDIO:
3309 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);
3310 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3311 message->param.audiopath = param->channel;
3312 message_put(message);
3316 /* JOIN sends a notify message */
3317 case MESSAGE_NOTIFY:
3318 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);
3319 join_notify(portlist, message_type, param);
3322 /* JOIN wants keypad / dtmf */
3323 case MESSAGE_ENABLEKEYPAD:
3324 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);
3327 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3331 /* JOIN sends a DTMF message */
3333 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);
3334 join_dtmf(portlist, message_type, param);
3337 /* JOIN sends a DISABLE_DEJITTER message */
3338 case MESSAGE_DISABLE_DEJITTER:
3339 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received disable dejitter.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3340 join_disable_dejitter(portlist, message_type, param);
3344 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);
3349 /* pick_join will connect the first incoming call found. the endpoint
3350 * will receivce a MESSAGE_CONNECT.
3352 int match_list(char *list, char *item)
3354 char *end, *next = NULL;
3356 /* no list make matching */
3361 /* eliminate white spaces */
3362 while (*list > '\0' && *list <= ' ')
3368 /* if end of list is reached, we return */
3369 if (list[0] == '\0')
3371 /* if we have more than one entry (left) */
3372 if ((end = strchr(list, ',')))
3375 next = end = strchr(list, '\0');
3376 while (*(end-1) <= ' ')
3378 /* if string part matches item */
3379 if (!strncmp(list, item, end-list))
3385 void EndpointAppPBX::pick_join(char *extensions)
3387 struct lcr_msg *message;
3388 struct port_list *portlist;
3390 class EndpointAppPBX *eapp, *found;
3392 class JoinPBX *joinpbx;
3393 struct join_relation *relation;
3395 /* find an endpoint that is ringing internally or vbox with higher priority */
3397 eapp = apppbx_first;
3399 if (eapp!=this && ea_endpoint->ep_portlist) {
3400 portlist = eapp->ea_endpoint->ep_portlist;
3402 if ((port = find_port_id(portlist->port_id))) {
3403 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3404 if (match_list(extensions, eapp->e_ext.number)) {
3409 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3410 && port->p_state==PORT_STATE_OUT_ALERTING)
3411 if (match_list(extensions, eapp->e_ext.number)) {
3415 portlist = portlist->next;
3423 /* if no endpoint found */
3425 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);
3427 set_tone(ea_endpoint->ep_portlist, "cause_10");
3428 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3429 new_state(EPOINT_STATE_OUT_DISCONNECT);
3434 if (ea_endpoint->ep_join_id) {
3435 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3438 if (!eapp->ea_endpoint->ep_join_id) {
3439 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3442 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3444 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3447 if (join->j_type != JOIN_TYPE_PBX) {
3448 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3451 joinpbx = (class JoinPBX *)join;
3452 relation = joinpbx->j_relation;
3454 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3457 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3458 relation = relation->next;
3460 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3465 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3467 if (options.deb & DEBUG_EPOINT) {
3468 class Join *debug_c = join_first;
3469 class Endpoint *debug_e = epoint_first;
3470 class Port *debug_p = port_first;
3472 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3474 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3476 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3477 debug_c = debug_c->next;
3479 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3481 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3482 debug_e = debug_e->next;
3484 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3486 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3487 debug_p = debug_p->next;
3492 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3493 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3494 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3496 /* connnecting our endpoint */
3497 new_state(EPOINT_STATE_CONNECT);
3498 if (e_ext.number[0])
3500 set_tone(ea_endpoint->ep_portlist, NULL);
3502 /* now we send a release to the ringing endpoint */
3503 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3504 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3505 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3506 message_put(message);
3508 /* we send a connect to the join with our caller id */
3509 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3510 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3511 message->param.connectinfo.present = e_callerinfo.present;
3512 message->param.connectinfo.screen = e_callerinfo.screen;
3513 message->param.connectinfo.itype = e_callerinfo.itype;
3514 message->param.connectinfo.ntype = e_callerinfo.ntype;
3515 message_put(message);
3517 /* we send a connect to our port with the remote callerid */
3518 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3519 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3520 message->param.connectinfo.present = eapp->e_callerinfo.present;
3521 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3522 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3523 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3524 /* handle restricted caller ids */
3525 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);
3526 /* display callerid if desired for extension */
3527 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));
3528 message_put(message);
3530 /* we send a connect to the audio path (not for vbox) */
3531 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3532 message->param.audiopath = 1;
3533 message_put(message);
3535 /* beeing paranoid, we make call update */
3536 trigger_work(&joinpbx->j_updatebridge);
3538 if (options.deb & DEBUG_EPOINT) {
3539 class Join *debug_c = join_first;
3540 class Endpoint *debug_e = epoint_first;
3541 class Port *debug_p = port_first;
3543 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3545 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3547 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3548 debug_c = debug_c->next;
3550 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3552 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3553 debug_e = debug_e->next;
3555 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3557 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3558 debug_p = debug_p->next;
3564 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3566 int EndpointAppPBX::join_join_dss1(void)
3569 struct lcr_msg *message;
3570 struct join_relation *add_relation, *remove_relation;
3571 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3572 class Join *our_join, *other_join, *add_join, *remove_join;
3573 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3574 class EndpointAppPBX *other_eapp, *remove_eapp;
3575 class Port *our_port, *other_port;
3576 class Pdss1 *our_pdss1, *other_pdss1;
3577 class Endpoint *temp_epoint;
3579 /* are we a candidate to join a join? */
3580 our_join = find_join_id(ea_endpoint->ep_join_id);
3582 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3585 if (our_join->j_type != JOIN_TYPE_PBX) {
3586 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3589 our_joinpbx = (class JoinPBX *)our_join;
3590 if (!ea_endpoint->ep_portlist) {
3591 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3594 if (!e_ext.number[0]) {
3595 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3598 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3600 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3603 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3604 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3607 our_pdss1 = (class Pdss1 *)our_port;
3609 /* find an endpoint that has the same mISDNport/ces that we are on */
3610 other_eapp = apppbx_first;
3612 if (other_eapp == this) {
3613 other_eapp = other_eapp->next;
3616 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);
3617 if (other_eapp->e_ext.number[0] /* has terminal */
3618 && other_eapp->ea_endpoint->ep_portlist /* has port */
3619 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3620 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3621 if (other_port) { /* port still exists */
3622 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3623 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3624 other_pdss1 = (class Pdss1 *)other_port;
3625 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);
3626 if (1 //other_pdss1->p_m_hold /* port is on hold */
3627 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3628 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3631 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3634 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3637 other_eapp = other_eapp->next;
3640 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3643 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3645 /* if we have the same join */
3646 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3647 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3650 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3652 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3655 if (other_join->j_type != JOIN_TYPE_PBX) {
3656 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3659 other_joinpbx = (class JoinPBX *)other_join;
3660 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3661 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3665 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3666 if (our_pdss1->p_m_hold && !other_pdss1->p_m_hold) {
3667 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) our relation is on hold and other is active, so we move our relations to other relations\n", ea_endpoint->ep_serial);
3669 remove_join = our_join;
3670 remove_joinpbx = our_joinpbx;
3671 add_join = other_join;
3672 add_joinpbx = other_joinpbx;
3674 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) our relation is active or other is on hold, so we move ohter relations to our relations\n", ea_endpoint->ep_serial);
3675 remove_eapp = other_eapp;
3676 remove_join = other_join;
3677 remove_joinpbx = other_joinpbx;
3678 add_join = our_join;
3679 add_joinpbx = our_joinpbx;
3682 /* remove relation to endpoint for join on hold */
3683 remove_relation = remove_joinpbx->j_relation;
3684 remove_relation_pointer = &remove_joinpbx->j_relation;
3685 while(remove_relation) {
3686 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3687 /* detach other endpoint */
3688 *remove_relation_pointer = remove_relation->next;
3689 FREE(remove_relation, sizeof(struct join_relation));
3691 remove_relation = *remove_relation_pointer;
3692 remove_eapp->ea_endpoint->ep_join_id = 0;
3696 /* change join/hold pointer of endpoint to the new join */
3697 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3699 if (temp_epoint->ep_join_id == remove_join->j_serial)
3700 temp_epoint->ep_join_id = add_join->j_serial;
3703 remove_relation_pointer = &remove_relation->next;
3704 remove_relation = remove_relation->next;
3706 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3708 /* join call relations */
3709 add_relation = add_joinpbx->j_relation;
3710 add_relation_pointer = &add_joinpbx->j_relation;
3711 while(add_relation) {
3712 add_relation_pointer = &add_relation->next;
3713 add_relation = add_relation->next;
3715 *add_relation_pointer = remove_joinpbx->j_relation;
3716 remove_joinpbx->j_relation = NULL;
3717 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3719 /* release endpoint */
3720 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3721 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3722 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3723 message_put(message);
3725 /* if we are not a partyline, we get partyline state from other join */
3726 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3728 /* remove empty join */
3730 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3732 /* mixer must update */
3733 trigger_work(&add_joinpbx->j_updatebridge);
3735 /* we send a retrieve to that endpoint */
3736 // mixer will update the hold-state of the join and send it to the endpoints is changes
3738 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3744 /* join calls (look for a join that is on hold (same fxs interface/terminal))
3746 int EndpointAppPBX::join_join_fxs(void)
3749 struct lcr_msg *message;
3750 struct join_relation *add_relation, *remove_relation;
3751 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3752 class Join *our_join, *other_join, *add_join, *remove_join;
3753 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3754 class EndpointAppPBX *other_eapp, *remove_eapp;
3755 class Port *our_port, *other_port;
3756 class Pfxs *our_fxs, *other_fxs;
3757 class Endpoint *temp_epoint;
3759 /* are we a candidate to join a join? */
3760 our_join = find_join_id(ea_endpoint->ep_join_id);
3762 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3765 if (our_join->j_type != JOIN_TYPE_PBX) {
3766 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3769 our_joinpbx = (class JoinPBX *)our_join;
3770 if (!ea_endpoint->ep_portlist) {
3771 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3774 if (!e_ext.number[0]) {
3775 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3778 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3780 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3783 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
3784 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not fxs.\n", ea_endpoint->ep_serial);
3787 our_fxs = (class Pfxs *)our_port;
3789 /* find an endpoint that has the same mISDNport that we are on */
3790 other_eapp = apppbx_first;
3792 if (other_eapp == this) {
3793 other_eapp = other_eapp->next;
3796 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);
3797 if (other_eapp->e_ext.number[0] /* has terminal */
3798 && other_eapp->ea_endpoint->ep_portlist /* has port */
3799 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3800 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3801 if (other_port) { /* port still exists */
3802 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
3803 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is FXS */
3804 other_fxs = (class Pfxs *)other_port;
3805 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 state=%d\n", ea_endpoint->ep_serial, our_fxs->p_m_mISDNport->portnum, other_fxs->p_m_mISDNport->portnum, (other_fxs->p_m_hold)?"YES":"NO", other_fxs->p_state);
3806 if (1 //other_fxs->p_m_hold /* port is on hold */
3807 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
3810 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3813 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3816 other_eapp = other_eapp->next;
3819 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
3822 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3824 /* if we have the same join */
3825 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3826 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3829 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3831 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3834 if (other_join->j_type != JOIN_TYPE_PBX) {
3835 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3838 other_joinpbx = (class JoinPBX *)other_join;
3839 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3840 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3844 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3845 if (our_fxs->p_m_hold && !other_fxs->p_m_hold) {
3846 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) our relation is on hold and other is active, so we move our relations to other relations\n", ea_endpoint->ep_serial);
3848 remove_join = our_join;
3849 remove_joinpbx = our_joinpbx;
3850 add_join = other_join;
3851 add_joinpbx = other_joinpbx;
3853 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) our relation is active or other is on hold, so we move ohter relations to our relations\n", ea_endpoint->ep_serial);
3854 remove_eapp = other_eapp;
3855 remove_join = other_join;
3856 remove_joinpbx = other_joinpbx;
3857 add_join = our_join;
3858 add_joinpbx = our_joinpbx;
3861 /* remove relation to endpoint for join on hold */
3862 remove_relation = remove_joinpbx->j_relation;
3863 remove_relation_pointer = &remove_joinpbx->j_relation;
3864 while(remove_relation) {
3865 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3866 /* detach other endpoint */
3867 *remove_relation_pointer = remove_relation->next;
3868 FREE(remove_relation, sizeof(struct join_relation));
3870 remove_relation = *remove_relation_pointer;
3871 remove_eapp->ea_endpoint->ep_join_id = 0;
3875 /* change join/hold pointer of endpoint to the new join */
3876 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3878 if (temp_epoint->ep_join_id == remove_join->j_serial)
3879 temp_epoint->ep_join_id = add_join->j_serial;
3882 remove_relation_pointer = &remove_relation->next;
3883 remove_relation = remove_relation->next;
3885 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3887 /* join call relations */
3888 add_relation = add_joinpbx->j_relation;
3889 add_relation_pointer = &add_joinpbx->j_relation;
3890 while(add_relation) {
3891 add_relation_pointer = &add_relation->next;
3892 add_relation = add_relation->next;
3894 *add_relation_pointer = remove_joinpbx->j_relation;
3895 remove_joinpbx->j_relation = NULL;
3896 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3898 /* release endpoint */
3899 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3900 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3901 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3902 message_put(message);
3904 /* if we are not a partyline, we get partyline state from other join */
3905 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3907 /* remove empty join */
3909 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3911 /* mixer must update */
3912 trigger_work(&add_joinpbx->j_updatebridge);
3914 /* we send a retrieve to that endpoint */
3915 // mixer will update the hold-state of the join and send it to the endpoints is changes
3917 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3923 int EndpointAppPBX::join_3pty_dss1(void)
3926 class Join *our_join, *other_join;
3927 class JoinPBX *our_joinpbx, *other_joinpbx;
3928 class EndpointAppPBX *other_eapp;
3929 class Port *our_port, *other_port;
3930 class Pdss1 *our_pdss1, *other_pdss1;
3932 /* are we a candidate to join a join? */
3933 our_join = find_join_id(ea_endpoint->ep_join_id);
3935 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3938 if (our_join->j_type != JOIN_TYPE_PBX) {
3939 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3942 our_joinpbx = (class JoinPBX *)our_join;
3943 if (!ea_endpoint->ep_portlist) {
3944 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3947 if (!e_ext.number[0]) {
3948 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3951 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3953 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3956 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3957 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3960 our_pdss1 = (class Pdss1 *)our_port;
3962 /* find an endpoint that has the same mISDNport/ces that we are on */
3963 other_eapp = apppbx_first;
3965 if (other_eapp == this) {
3966 other_eapp = other_eapp->next;
3969 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);
3970 if (other_eapp->e_ext.number[0] /* has terminal */
3971 && other_eapp->ea_endpoint->ep_portlist /* has port */
3972 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3973 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3974 if (other_port) { /* port still exists */
3975 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3976 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3977 other_pdss1 = (class Pdss1 *)other_port;
3978 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);
3979 if (1 //other_pdss1->p_m_hold /* port is on hold */
3980 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3981 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3984 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3987 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3990 other_eapp = other_eapp->next;
3993 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3996 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3998 /* if we have the same join */
3999 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4000 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4003 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4005 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4008 if (other_join->j_type != JOIN_TYPE_PBX) {
4009 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4012 other_joinpbx = (class JoinPBX *)other_join;
4013 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4014 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4018 if (our_joinpbx->j_3pty) {
4019 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4022 if (other_joinpbx->j_3pty) {
4023 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4027 /* set 3PTY bridge */
4028 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4029 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4031 /* mixer must update */
4032 trigger_work(&our_joinpbx->j_updatebridge);
4033 trigger_work(&other_joinpbx->j_updatebridge);
4035 /* we send a retrieve to that endpoint */
4036 // mixer will update the hold-state of the join and send it to the endpoints is changes
4038 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4044 int EndpointAppPBX::join_3pty_fxs(void)
4047 class Join *our_join, *other_join;
4048 class JoinPBX *our_joinpbx, *other_joinpbx;
4049 class EndpointAppPBX *other_eapp;
4050 class Port *our_port, *other_port;
4051 class Pfxs *our_fxs, *other_fxs;
4053 /* are we a candidate to join a join? */
4054 our_join = find_join_id(ea_endpoint->ep_join_id);
4056 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4059 if (our_join->j_type != JOIN_TYPE_PBX) {
4060 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4063 our_joinpbx = (class JoinPBX *)our_join;
4064 if (!ea_endpoint->ep_portlist) {
4065 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4068 if (!e_ext.number[0]) {
4069 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4072 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4074 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4077 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
4078 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not FXS pots.\n", ea_endpoint->ep_serial);
4081 our_fxs = (class Pfxs *)our_port;
4083 /* find an endpoint that has the same mISDNport that we are on */
4084 other_eapp = apppbx_first;
4086 if (other_eapp == this) {
4087 other_eapp = other_eapp->next;
4090 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);
4091 if (other_eapp->e_ext.number[0] /* has terminal */
4092 && other_eapp->ea_endpoint->ep_portlist /* has port */
4093 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4094 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4095 if (other_port) { /* port still exists */
4096 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4097 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is isdn nt-mode */
4098 other_fxs = (class Pfxs *)other_port;
4099 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type FXS! comparing our portnum=%d with other's portnum=%d hold=%s state=%d\n", ea_endpoint->ep_serial, our_fxs->p_m_mISDNport->portnum, other_fxs->p_m_mISDNport->portnum, (other_fxs->p_m_hold)?"YES":"NO", other_fxs->p_state);
4100 if (1 //other_fxs->p_m_hold /* port is on hold */
4101 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
4104 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4107 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4110 other_eapp = other_eapp->next;
4113 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4116 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4118 /* if we have the same join */
4119 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4120 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4123 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4125 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4128 if (other_join->j_type != JOIN_TYPE_PBX) {
4129 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4132 other_joinpbx = (class JoinPBX *)other_join;
4133 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4134 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4138 if (our_joinpbx->j_3pty) {
4139 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4142 if (other_joinpbx->j_3pty) {
4143 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4147 /* set 3PTY bridge */
4148 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4149 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4151 /* mixer must update */
4152 trigger_work(&our_joinpbx->j_updatebridge);
4153 trigger_work(&other_joinpbx->j_updatebridge);
4155 /* we send a retrieve to that endpoint */
4156 // mixer will update the hold-state of the join and send it to the endpoints is changes
4158 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4164 int EndpointAppPBX::split_3pty(void)
4167 class Join *our_join, *other_join;
4168 class JoinPBX *our_joinpbx, *other_joinpbx;
4170 /* are we a candidate to join a join? */
4171 our_join = find_join_id(ea_endpoint->ep_join_id);
4173 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4176 if (our_join->j_type != JOIN_TYPE_PBX) {
4177 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4180 our_joinpbx = (class JoinPBX *)our_join;
4182 if (!our_joinpbx->j_3pty) {
4183 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
4187 other_join = find_join_id(our_joinpbx->j_3pty);
4189 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4192 if (other_join->j_type != JOIN_TYPE_PBX) {
4193 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4196 other_joinpbx = (class JoinPBX *)other_join;
4198 our_joinpbx->j_3pty = 0;
4199 other_joinpbx->j_3pty = 0;
4201 /* mixer must update */
4202 trigger_work(&our_joinpbx->j_updatebridge);
4203 trigger_work(&other_joinpbx->j_updatebridge);
4205 /* we send a retrieve to that endpoint */
4206 // mixer will update the hold-state of the join and send it to the endpoints is changes
4208 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4214 /* check if we have an external call
4215 * this is used to check for encryption ability
4217 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
4219 struct join_relation *relation;
4221 class JoinPBX *joinpbx;
4222 class Endpoint *epoint;
4224 /* some paranoia check */
4225 if (!ea_endpoint->ep_portlist) {
4226 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4227 *errstr = "No Call";
4230 if (!e_ext.number[0]) {
4231 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4232 *errstr = "No Call";
4236 /* check if we have a join with 2 parties */
4237 join = find_join_id(ea_endpoint->ep_join_id);
4239 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
4240 *errstr = "No Call";
4243 if (join->j_type != JOIN_TYPE_PBX) {
4244 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4245 *errstr = "No PBX Call";
4248 joinpbx = (class JoinPBX *)join;
4249 relation = joinpbx->j_relation;
4251 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4252 *errstr = "No Call";
4255 if (!relation->next) {
4256 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4257 *errstr = "No Call";
4260 if (relation->next->next) {
4261 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4262 *errstr = "Err: Conference";
4265 if (relation->epoint_id == ea_endpoint->ep_serial) {
4266 relation = relation->next;
4267 if (relation->epoint_id == ea_endpoint->ep_serial) {
4268 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4269 *errstr = "Software Error";
4274 /* check remote port for external call */
4275 epoint = find_epoint_id(relation->epoint_id);
4277 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4278 *errstr = "No Call";
4281 if (!epoint->ep_portlist) {
4282 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4283 *errstr = "No Call";
4286 *port = find_port_id(epoint->ep_portlist->port_id);
4288 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4289 *errstr = "No Call";
4292 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4293 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4294 *errstr = "No Ext Call";
4297 if ((*port)->p_state != PORT_STATE_CONNECT) {
4298 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4299 *errstr = "No Ext Connect";
4305 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4307 const char *logtext = "unknown";
4310 switch(message_type) {
4312 trace_header("SETUP", dir);
4313 if (dir == DIRECTION_OUT)
4314 add_trace("to", NULL, "CH(%lu)", port_id);
4315 if (dir == DIRECTION_IN)
4316 add_trace("from", NULL, "CH(%lu)", port_id);
4317 if (param->setup.callerinfo.extension[0])
4318 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4319 if (param->setup.callerinfo.interface[0])
4320 add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
4321 if (param->setup.dialinginfo.interfaces[0])
4322 add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
4323 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4324 switch(param->setup.callerinfo.present) {
4325 case INFO_PRESENT_RESTRICTED:
4326 add_trace("caller id", "present", "restricted");
4328 case INFO_PRESENT_ALLOWED:
4329 add_trace("caller id", "present", "allowed");
4332 add_trace("caller id", "present", "not available");
4334 if (param->setup.callerinfo.ntype2) {
4335 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4336 switch(param->setup.callerinfo.present) {
4337 case INFO_PRESENT_RESTRICTED:
4338 add_trace("caller id2", "present", "restricted");
4340 case INFO_PRESENT_ALLOWED:
4341 add_trace("caller id2", "present", "allowed");
4344 add_trace("caller id2", "present", "not available");
4347 if (param->setup.redirinfo.id[0]) {
4348 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4349 switch(param->setup.redirinfo.present) {
4350 case INFO_PRESENT_RESTRICTED:
4351 add_trace("redir'ing", "present", "restricted");
4353 case INFO_PRESENT_ALLOWED:
4354 add_trace("redir'ing", "present", "allowed");
4357 add_trace("redir'ing", "present", "not available");
4360 if (param->setup.dialinginfo.id[0])
4361 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4362 if (param->setup.dialinginfo.keypad[0])
4363 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4364 if (param->setup.dialinginfo.display[0])
4365 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4366 if (param->setup.dialinginfo.sending_complete)
4367 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4371 case MESSAGE_OVERLAP:
4372 trace_header("SETUP ACKNOWLEDGE", dir);
4373 if (dir == DIRECTION_OUT)
4374 add_trace("to", NULL, "CH(%lu)", port_id);
4375 if (dir == DIRECTION_IN)
4376 add_trace("from", NULL, "CH(%lu)", port_id);
4380 case MESSAGE_PROCEEDING:
4381 trace_header("PROCEEDING", dir);
4382 if (dir == DIRECTION_OUT)
4383 add_trace("to", NULL, "CH(%lu)", port_id);
4384 if (dir == DIRECTION_IN)
4385 add_trace("from", NULL, "CH(%lu)", port_id);
4389 case MESSAGE_ALERTING:
4390 trace_header("ALERTING", dir);
4391 if (dir == DIRECTION_OUT)
4392 add_trace("to", NULL, "CH(%lu)", port_id);
4393 if (dir == DIRECTION_IN)
4394 add_trace("from", NULL, "CH(%lu)", port_id);
4398 case MESSAGE_CONNECT:
4399 trace_header("CONNECT", dir);
4400 if (dir == DIRECTION_OUT)
4401 add_trace("to", NULL, "CH(%lu)", port_id);
4402 if (dir == DIRECTION_IN)
4403 add_trace("from", NULL, "CH(%lu)", port_id);
4404 if (param->connectinfo.extension[0])
4405 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4406 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4407 switch(param->connectinfo.present) {
4408 case INFO_PRESENT_RESTRICTED:
4409 add_trace("connect id", "present", "restricted");
4411 case INFO_PRESENT_ALLOWED:
4412 add_trace("connect id", "present", "allowed");
4415 add_trace("connect id", "present", "not available");
4417 if (param->connectinfo.display[0])
4418 add_trace("display", NULL, "%s", param->connectinfo.display);
4422 case MESSAGE_DISCONNECT:
4423 case MESSAGE_RELEASE:
4424 if (message_type == MESSAGE_DISCONNECT)
4425 trace_header("DISCONNECT", dir);
4427 trace_header("RELEASE", dir);
4428 if (dir == DIRECTION_OUT)
4429 add_trace("to", NULL, "CH(%lu)", port_id);
4430 if (dir == DIRECTION_IN)
4431 add_trace("from", NULL, "CH(%lu)", port_id);
4432 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4433 switch(param->disconnectinfo.location) {
4435 add_trace("cause", "location", "0-User");
4437 case LOCATION_PRIVATE_LOCAL:
4438 add_trace("cause", "location", "1-Local-PBX");
4440 case LOCATION_PUBLIC_LOCAL:
4441 add_trace("cause", "location", "2-Local-Exchange");
4443 case LOCATION_TRANSIT:
4444 add_trace("cause", "location", "3-Transit");
4446 case LOCATION_PUBLIC_REMOTE:
4447 add_trace("cause", "location", "4-Remote-Exchange");
4449 case LOCATION_PRIVATE_REMOTE:
4450 add_trace("cause", "location", "5-Remote-PBX");
4452 case LOCATION_INTERNATIONAL:
4453 add_trace("cause", "location", "7-International-Exchange");
4455 case LOCATION_BEYOND:
4456 add_trace("cause", "location", "10-Beyond-Interworking");
4459 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4461 if (param->disconnectinfo.display[0])
4462 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4466 case MESSAGE_NOTIFY:
4467 switch(param->notifyinfo.notify) {
4472 logtext = "USER_SUSPENDED";
4475 logtext = "BEARER_SERVICE_CHANGED";
4478 logtext = "USER_RESUMED";
4481 logtext = "CONFERENCE_ESTABLISHED";
4484 logtext = "CONFERENCE_DISCONNECTED";
4487 logtext = "OTHER_PARTY_ADDED";
4490 logtext = "ISOLATED";
4493 logtext = "REATTACHED";
4496 logtext = "OTHER_PARTY_ISOLATED";
4499 logtext = "OTHER_PARTY_REATTACHED";
4502 logtext = "OTHER_PARTY_SPLIT";
4505 logtext = "OTHER_PARTY_DISCONNECTED";
4508 logtext = "CONFERENCE_FLOATING";
4511 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4514 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4517 logtext = "CALL_IS_A_WAITING_CALL";
4520 logtext = "DIVERSION_ACTIVATED";
4523 logtext = "RESERVED_CT_1";
4526 logtext = "RESERVED_CT_2";
4529 logtext = "REVERSE_CHARGING";
4532 logtext = "REMOTE_HOLD";
4535 logtext = "REMOTE_RETRIEVAL";
4538 logtext = "CALL_IS_DIVERTING";
4541 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4545 trace_header("NOTIFY", dir);
4546 if (dir == DIRECTION_OUT)
4547 add_trace("to", NULL, "CH(%lu)", port_id);
4548 if (dir == DIRECTION_IN)
4549 add_trace("from", NULL, "CH(%lu)", port_id);
4550 if (param->notifyinfo.notify)
4551 add_trace("indicator", NULL, "%s", logtext);
4552 if (param->notifyinfo.id[0]) {
4553 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4554 switch(param->notifyinfo.present) {
4555 case INFO_PRESENT_RESTRICTED:
4556 add_trace("redir'on", "present", "restricted");
4558 case INFO_PRESENT_ALLOWED:
4559 add_trace("redir'on", "present", "allowed");
4562 add_trace("redir'on", "present", "not available");
4565 if (param->notifyinfo.display[0])
4566 add_trace("display", NULL, "%s", param->notifyinfo.display);
4570 case MESSAGE_PROGRESS:
4571 switch(param->progressinfo.progress) {
4573 logtext = "Call is not end to end ISDN";
4576 logtext = "Destination address is non-ISDN";
4579 logtext = "Origination address is non-ISDN";
4582 logtext = "Call has returned to the ISDN";
4585 logtext = "In-band info or pattern available";
4588 SPRINT(buffer, "%d", param->progressinfo.progress);
4592 trace_header("PROGRESS", dir);
4593 if (dir == DIRECTION_OUT)
4594 add_trace("to", NULL, "CH(%lu)", port_id);
4595 if (dir == DIRECTION_IN)
4596 add_trace("from", NULL, "CH(%lu)", port_id);
4597 add_trace("indicator", NULL, "%s", logtext);
4598 switch(param->progressinfo.location) {
4600 add_trace("cause", "location", "0-User");
4602 case LOCATION_PRIVATE_LOCAL:
4603 add_trace("cause", "location", "1-Local-PBX");
4605 case LOCATION_PUBLIC_LOCAL:
4606 add_trace("cause", "location", "2-Local-Exchange");
4608 case LOCATION_TRANSIT:
4609 add_trace("cause", "location", "3-Transit");
4611 case LOCATION_PUBLIC_REMOTE:
4612 add_trace("cause", "location", "4-Remote-Exchange");
4614 case LOCATION_PRIVATE_REMOTE:
4615 add_trace("cause", "location", "5-Remote-PBX");
4617 case LOCATION_INTERNATIONAL:
4618 add_trace("cause", "location", "7-International-Exchange");
4620 case LOCATION_BEYOND:
4621 add_trace("cause", "location", "10-Beyond-Interworking");
4624 add_trace("cause", "location", "%d", param->progressinfo.location);
4629 case MESSAGE_INFORMATION:
4630 trace_header("INFORMATION", dir);
4631 if (dir == DIRECTION_OUT)
4632 add_trace("to", NULL, "CH(%lu)", port_id);
4633 if (dir == DIRECTION_IN)
4634 add_trace("from", NULL, "CH(%lu)", port_id);
4635 if (param->information.id[0])
4636 add_trace("dialing", NULL, "%s", param->information.id);
4637 if (param->information.display[0])
4638 add_trace("display", NULL, "%s", param->information.display);
4639 if (param->information.sending_complete)
4640 add_trace("complete", NULL, "true", param->information.sending_complete);
4644 case MESSAGE_FACILITY:
4645 trace_header("FACILITY", dir);
4646 if (dir == DIRECTION_OUT)
4647 add_trace("to", NULL, "CH(%lu)", port_id);
4648 if (dir == DIRECTION_IN)
4649 add_trace("from", NULL, "CH(%lu)", port_id);
4654 trace_header("TONE", dir);
4655 if (dir == DIRECTION_OUT)
4656 add_trace("to", NULL, "CH(%lu)", port_id);
4657 if (dir == DIRECTION_IN)
4658 add_trace("from", NULL, "CH(%lu)", port_id);
4659 if (param->tone.name[0]) {
4660 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4661 add_trace("name", NULL, "%s", param->tone.name);
4663 add_trace("off", NULL, NULL);
4667 case MESSAGE_SUSPEND:
4668 case MESSAGE_RESUME:
4669 if (message_type == MESSAGE_SUSPEND)
4670 trace_header("SUSPEND", dir);
4672 trace_header("RESUME", dir);
4673 if (dir == DIRECTION_OUT)
4674 add_trace("to", NULL, "CH(%lu)", port_id);
4675 if (dir == DIRECTION_IN)
4676 add_trace("from", NULL, "CH(%lu)", port_id);
4677 if (param->parkinfo.len)
4678 add_trace("length", NULL, "%d", param->parkinfo.len);
4683 case MESSAGE_BCHANNEL:
4684 trace_header("BCHANNEL", dir);
4685 switch(param->bchannel.type) {
4686 case BCHANNEL_REQUEST:
4687 add_trace("type", NULL, "request");
4689 case BCHANNEL_ASSIGN:
4690 add_trace("type", NULL, "assign");
4692 case BCHANNEL_ASSIGN_ACK:
4693 add_trace("type", NULL, "assign_ack");
4695 case BCHANNEL_REMOVE:
4696 add_trace("type", NULL, "remove");
4698 case BCHANNEL_REMOVE_ACK:
4699 add_trace("type", NULL, "remove_ack");
4702 if (param->bchannel.addr)
4703 add_trace("address", NULL, "%x", param->bchannel.addr);
4709 if (param->threepty.begin)
4710 trace_header("Begin3PTY", dir);
4711 if (param->threepty.end)
4712 trace_header("End3PTY", dir);
4713 if (param->threepty.invoke)
4714 add_trace("action", NULL, "invoke");
4715 if (param->threepty.result)
4716 add_trace("action", NULL, "result");
4717 if (param->threepty.error)
4718 add_trace("action", NULL, "error");
4719 add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id);
4723 case MESSAGE_TRANSFER:
4724 trace_header("TRANSFER", dir);
4728 case MESSAGE_DISABLE_DEJITTER:
4729 trace_header("DISBALE_DEJITTER", dir);
4731 add_trace("queue", NULL, "%d", param->queue);
4736 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4740 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4742 struct lcr_msg *message;
4746 if (!portlist->port_id)
4749 if (!e_connectedmode) {
4750 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4751 message->param.disconnectinfo.cause = cause;
4752 message->param.disconnectinfo.location = location;
4754 SCPY(message->param.disconnectinfo.display, display);
4756 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4758 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4760 SCPY(message->param.notifyinfo.display, display);
4762 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4764 message_put(message);
4765 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);