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;
3396 /* find an endpoint that is ringing internally or vbox with higher priority */
3399 eapp = apppbx_first;
3401 if (eapp!=this && ea_endpoint->ep_portlist) {
3402 portlist = eapp->ea_endpoint->ep_portlist;
3404 if ((port = find_port_id(portlist->port_id))) {
3405 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3406 if (match_list(extensions, eapp->e_ext.number)) {
3412 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3413 && port->p_state==PORT_STATE_OUT_ALERTING)
3414 if (match_list(extensions, eapp->e_ext.number)) {
3418 portlist = portlist->next;
3426 /* if no endpoint found */
3428 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);
3430 set_tone(ea_endpoint->ep_portlist, "cause_10");
3431 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3432 new_state(EPOINT_STATE_OUT_DISCONNECT);
3437 if (ea_endpoint->ep_join_id) {
3438 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3441 if (!eapp->ea_endpoint->ep_join_id) {
3442 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3445 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3447 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3450 if (join->j_type != JOIN_TYPE_PBX) {
3451 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3454 joinpbx = (class JoinPBX *)join;
3455 relation = joinpbx->j_relation;
3457 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3460 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3461 relation = relation->next;
3463 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3468 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3470 if (options.deb & DEBUG_EPOINT) {
3471 class Join *debug_c = join_first;
3472 class Endpoint *debug_e = epoint_first;
3473 class Port *debug_p = port_first;
3475 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3477 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3479 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3480 debug_c = debug_c->next;
3482 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3484 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3485 debug_e = debug_e->next;
3487 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3489 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3490 debug_p = debug_p->next;
3495 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3496 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3497 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3499 /* connnecting our endpoint */
3500 new_state(EPOINT_STATE_CONNECT);
3501 if (e_ext.number[0])
3503 set_tone(ea_endpoint->ep_portlist, NULL);
3505 /* now we send a release to the ringing endpoint */
3506 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3507 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3508 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3509 message_put(message);
3511 /* we send a connect to the join with our caller id */
3512 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3513 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3514 message->param.connectinfo.present = e_callerinfo.present;
3515 message->param.connectinfo.screen = e_callerinfo.screen;
3516 message->param.connectinfo.itype = e_callerinfo.itype;
3517 message->param.connectinfo.ntype = e_callerinfo.ntype;
3518 message_put(message);
3520 /* we send a connect to our port with the remote callerid */
3521 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3522 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3523 message->param.connectinfo.present = eapp->e_callerinfo.present;
3524 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3525 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3526 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3527 /* handle restricted caller ids */
3528 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);
3529 /* display callerid if desired for extension */
3530 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));
3531 message_put(message);
3533 /* we send a connect to the audio path (not for vbox) */
3534 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3535 message->param.audiopath = 1;
3536 message_put(message);
3538 /* beeing paranoid, we make call update */
3539 trigger_work(&joinpbx->j_updatebridge);
3541 if (options.deb & DEBUG_EPOINT) {
3542 class Join *debug_c = join_first;
3543 class Endpoint *debug_e = epoint_first;
3544 class Port *debug_p = port_first;
3546 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3548 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3550 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3551 debug_c = debug_c->next;
3553 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3555 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3556 debug_e = debug_e->next;
3558 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3560 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3561 debug_p = debug_p->next;
3567 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3569 int EndpointAppPBX::join_join_dss1(void)
3572 struct lcr_msg *message;
3573 struct join_relation *add_relation, *remove_relation;
3574 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3575 class Join *our_join, *other_join, *add_join, *remove_join;
3576 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3577 class EndpointAppPBX *other_eapp, *remove_eapp;
3578 class Port *our_port, *other_port;
3579 class Pdss1 *our_pdss1, *other_pdss1;
3580 class Endpoint *temp_epoint;
3582 /* are we a candidate to join a join? */
3583 our_join = find_join_id(ea_endpoint->ep_join_id);
3585 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3588 if (our_join->j_type != JOIN_TYPE_PBX) {
3589 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3592 our_joinpbx = (class JoinPBX *)our_join;
3593 if (!ea_endpoint->ep_portlist) {
3594 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3597 if (!e_ext.number[0]) {
3598 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3601 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3603 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3606 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3607 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3610 our_pdss1 = (class Pdss1 *)our_port;
3612 /* find an endpoint that has the same mISDNport/ces that we are on */
3613 other_eapp = apppbx_first;
3615 if (other_eapp == this) {
3616 other_eapp = other_eapp->next;
3619 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);
3620 if (other_eapp->e_ext.number[0] /* has terminal */
3621 && other_eapp->ea_endpoint->ep_portlist /* has port */
3622 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3623 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3624 if (other_port) { /* port still exists */
3625 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3626 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3627 other_pdss1 = (class Pdss1 *)other_port;
3628 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);
3629 if (1 //other_pdss1->p_m_hold /* port is on hold */
3630 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3631 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3634 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3637 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3640 other_eapp = other_eapp->next;
3643 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3646 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3648 /* if we have the same join */
3649 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3650 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3653 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3655 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3658 if (other_join->j_type != JOIN_TYPE_PBX) {
3659 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3662 other_joinpbx = (class JoinPBX *)other_join;
3663 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3664 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3668 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3669 if (our_pdss1->p_m_hold && !other_pdss1->p_m_hold) {
3670 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);
3672 remove_join = our_join;
3673 remove_joinpbx = our_joinpbx;
3674 add_join = other_join;
3675 add_joinpbx = other_joinpbx;
3677 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);
3678 remove_eapp = other_eapp;
3679 remove_join = other_join;
3680 remove_joinpbx = other_joinpbx;
3681 add_join = our_join;
3682 add_joinpbx = our_joinpbx;
3685 /* remove relation to endpoint for join on hold */
3686 remove_relation = remove_joinpbx->j_relation;
3687 remove_relation_pointer = &remove_joinpbx->j_relation;
3688 while(remove_relation) {
3689 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3690 /* detach other endpoint */
3691 *remove_relation_pointer = remove_relation->next;
3692 FREE(remove_relation, sizeof(struct join_relation));
3694 remove_relation = *remove_relation_pointer;
3695 remove_eapp->ea_endpoint->ep_join_id = 0;
3699 /* change join/hold pointer of endpoint to the new join */
3700 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3702 if (temp_epoint->ep_join_id == remove_join->j_serial)
3703 temp_epoint->ep_join_id = add_join->j_serial;
3706 remove_relation_pointer = &remove_relation->next;
3707 remove_relation = remove_relation->next;
3709 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3711 /* join call relations */
3712 add_relation = add_joinpbx->j_relation;
3713 add_relation_pointer = &add_joinpbx->j_relation;
3714 while(add_relation) {
3715 add_relation_pointer = &add_relation->next;
3716 add_relation = add_relation->next;
3718 *add_relation_pointer = remove_joinpbx->j_relation;
3719 remove_joinpbx->j_relation = NULL;
3720 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3722 /* release endpoint */
3723 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3724 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3725 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3726 message_put(message);
3728 /* if we are not a partyline, we get partyline state from other join */
3729 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3731 /* remove empty join */
3733 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3735 /* mixer must update */
3736 trigger_work(&add_joinpbx->j_updatebridge);
3738 /* we send a retrieve to that endpoint */
3739 // mixer will update the hold-state of the join and send it to the endpoints is changes
3741 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3747 /* join calls (look for a join that is on hold (same fxs interface/terminal))
3749 int EndpointAppPBX::join_join_fxs(void)
3752 struct lcr_msg *message;
3753 struct join_relation *add_relation, *remove_relation;
3754 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3755 class Join *our_join, *other_join, *add_join, *remove_join;
3756 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3757 class EndpointAppPBX *other_eapp, *remove_eapp;
3758 class Port *our_port, *other_port;
3759 class Pfxs *our_fxs, *other_fxs;
3760 class Endpoint *temp_epoint;
3762 /* are we a candidate to join a join? */
3763 our_join = find_join_id(ea_endpoint->ep_join_id);
3765 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3768 if (our_join->j_type != JOIN_TYPE_PBX) {
3769 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3772 our_joinpbx = (class JoinPBX *)our_join;
3773 if (!ea_endpoint->ep_portlist) {
3774 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3777 if (!e_ext.number[0]) {
3778 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3781 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3783 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3786 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
3787 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not fxs.\n", ea_endpoint->ep_serial);
3790 our_fxs = (class Pfxs *)our_port;
3792 /* find an endpoint that has the same mISDNport that we are on */
3793 other_eapp = apppbx_first;
3795 if (other_eapp == this) {
3796 other_eapp = other_eapp->next;
3799 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);
3800 if (other_eapp->e_ext.number[0] /* has terminal */
3801 && other_eapp->ea_endpoint->ep_portlist /* has port */
3802 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3803 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3804 if (other_port) { /* port still exists */
3805 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
3806 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is FXS */
3807 other_fxs = (class Pfxs *)other_port;
3808 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);
3809 if (1 //other_fxs->p_m_hold /* port is on hold */
3810 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
3813 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3816 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3819 other_eapp = other_eapp->next;
3822 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
3825 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3827 /* if we have the same join */
3828 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3829 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3832 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3834 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3837 if (other_join->j_type != JOIN_TYPE_PBX) {
3838 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3841 other_joinpbx = (class JoinPBX *)other_join;
3842 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3843 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3847 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3848 if (our_fxs->p_m_hold && !other_fxs->p_m_hold) {
3849 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);
3851 remove_join = our_join;
3852 remove_joinpbx = our_joinpbx;
3853 add_join = other_join;
3854 add_joinpbx = other_joinpbx;
3856 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);
3857 remove_eapp = other_eapp;
3858 remove_join = other_join;
3859 remove_joinpbx = other_joinpbx;
3860 add_join = our_join;
3861 add_joinpbx = our_joinpbx;
3864 /* remove relation to endpoint for join on hold */
3865 remove_relation = remove_joinpbx->j_relation;
3866 remove_relation_pointer = &remove_joinpbx->j_relation;
3867 while(remove_relation) {
3868 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3869 /* detach other endpoint */
3870 *remove_relation_pointer = remove_relation->next;
3871 FREE(remove_relation, sizeof(struct join_relation));
3873 remove_relation = *remove_relation_pointer;
3874 remove_eapp->ea_endpoint->ep_join_id = 0;
3878 /* change join/hold pointer of endpoint to the new join */
3879 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3881 if (temp_epoint->ep_join_id == remove_join->j_serial)
3882 temp_epoint->ep_join_id = add_join->j_serial;
3885 remove_relation_pointer = &remove_relation->next;
3886 remove_relation = remove_relation->next;
3888 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3890 /* join call relations */
3891 add_relation = add_joinpbx->j_relation;
3892 add_relation_pointer = &add_joinpbx->j_relation;
3893 while(add_relation) {
3894 add_relation_pointer = &add_relation->next;
3895 add_relation = add_relation->next;
3897 *add_relation_pointer = remove_joinpbx->j_relation;
3898 remove_joinpbx->j_relation = NULL;
3899 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3901 /* release endpoint */
3902 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3903 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3904 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3905 message_put(message);
3907 /* if we are not a partyline, we get partyline state from other join */
3908 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3910 /* remove empty join */
3912 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3914 /* mixer must update */
3915 trigger_work(&add_joinpbx->j_updatebridge);
3917 /* we send a retrieve to that endpoint */
3918 // mixer will update the hold-state of the join and send it to the endpoints is changes
3920 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3926 int EndpointAppPBX::join_3pty_dss1(void)
3929 class Join *our_join, *other_join;
3930 class JoinPBX *our_joinpbx, *other_joinpbx;
3931 class EndpointAppPBX *other_eapp;
3932 class Port *our_port, *other_port;
3933 class Pdss1 *our_pdss1, *other_pdss1;
3935 /* are we a candidate to join a join? */
3936 our_join = find_join_id(ea_endpoint->ep_join_id);
3938 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3941 if (our_join->j_type != JOIN_TYPE_PBX) {
3942 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3945 our_joinpbx = (class JoinPBX *)our_join;
3946 if (!ea_endpoint->ep_portlist) {
3947 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3950 if (!e_ext.number[0]) {
3951 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3954 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3956 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3959 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3960 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3963 our_pdss1 = (class Pdss1 *)our_port;
3965 /* find an endpoint that has the same mISDNport/ces that we are on */
3966 other_eapp = apppbx_first;
3968 if (other_eapp == this) {
3969 other_eapp = other_eapp->next;
3972 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);
3973 if (other_eapp->e_ext.number[0] /* has terminal */
3974 && other_eapp->ea_endpoint->ep_portlist /* has port */
3975 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3976 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3977 if (other_port) { /* port still exists */
3978 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3979 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3980 other_pdss1 = (class Pdss1 *)other_port;
3981 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);
3982 if (1 //other_pdss1->p_m_hold /* port is on hold */
3983 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3984 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3987 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3990 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3993 other_eapp = other_eapp->next;
3996 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3999 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4001 /* if we have the same join */
4002 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4003 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4006 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4008 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4011 if (other_join->j_type != JOIN_TYPE_PBX) {
4012 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4015 other_joinpbx = (class JoinPBX *)other_join;
4016 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4017 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4021 if (our_joinpbx->j_3pty) {
4022 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4025 if (other_joinpbx->j_3pty) {
4026 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4030 /* set 3PTY bridge */
4031 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4032 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4034 /* mixer must update */
4035 trigger_work(&our_joinpbx->j_updatebridge);
4036 trigger_work(&other_joinpbx->j_updatebridge);
4038 /* we send a retrieve to that endpoint */
4039 // mixer will update the hold-state of the join and send it to the endpoints is changes
4041 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4047 int EndpointAppPBX::join_3pty_fxs(void)
4050 class Join *our_join, *other_join;
4051 class JoinPBX *our_joinpbx, *other_joinpbx;
4052 class EndpointAppPBX *other_eapp;
4053 class Port *our_port, *other_port;
4054 class Pfxs *our_fxs, *other_fxs;
4056 /* are we a candidate to join a join? */
4057 our_join = find_join_id(ea_endpoint->ep_join_id);
4059 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4062 if (our_join->j_type != JOIN_TYPE_PBX) {
4063 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4066 our_joinpbx = (class JoinPBX *)our_join;
4067 if (!ea_endpoint->ep_portlist) {
4068 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4071 if (!e_ext.number[0]) {
4072 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4075 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4077 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4080 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
4081 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not FXS pots.\n", ea_endpoint->ep_serial);
4084 our_fxs = (class Pfxs *)our_port;
4086 /* find an endpoint that has the same mISDNport that we are on */
4087 other_eapp = apppbx_first;
4089 if (other_eapp == this) {
4090 other_eapp = other_eapp->next;
4093 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);
4094 if (other_eapp->e_ext.number[0] /* has terminal */
4095 && other_eapp->ea_endpoint->ep_portlist /* has port */
4096 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4097 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4098 if (other_port) { /* port still exists */
4099 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4100 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is isdn nt-mode */
4101 other_fxs = (class Pfxs *)other_port;
4102 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);
4103 if (1 //other_fxs->p_m_hold /* port is on hold */
4104 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
4107 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4110 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4113 other_eapp = other_eapp->next;
4116 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4119 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4121 /* if we have the same join */
4122 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4123 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4126 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4128 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4131 if (other_join->j_type != JOIN_TYPE_PBX) {
4132 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4135 other_joinpbx = (class JoinPBX *)other_join;
4136 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4137 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4141 if (our_joinpbx->j_3pty) {
4142 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4145 if (other_joinpbx->j_3pty) {
4146 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4150 /* set 3PTY bridge */
4151 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4152 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4154 /* mixer must update */
4155 trigger_work(&our_joinpbx->j_updatebridge);
4156 trigger_work(&other_joinpbx->j_updatebridge);
4158 /* we send a retrieve to that endpoint */
4159 // mixer will update the hold-state of the join and send it to the endpoints is changes
4161 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4167 int EndpointAppPBX::split_3pty(void)
4170 class Join *our_join, *other_join;
4171 class JoinPBX *our_joinpbx, *other_joinpbx;
4173 /* are we a candidate to join a join? */
4174 our_join = find_join_id(ea_endpoint->ep_join_id);
4176 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4179 if (our_join->j_type != JOIN_TYPE_PBX) {
4180 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4183 our_joinpbx = (class JoinPBX *)our_join;
4185 if (!our_joinpbx->j_3pty) {
4186 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
4190 other_join = find_join_id(our_joinpbx->j_3pty);
4192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4195 if (other_join->j_type != JOIN_TYPE_PBX) {
4196 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4199 other_joinpbx = (class JoinPBX *)other_join;
4201 our_joinpbx->j_3pty = 0;
4202 other_joinpbx->j_3pty = 0;
4204 /* mixer must update */
4205 trigger_work(&our_joinpbx->j_updatebridge);
4206 trigger_work(&other_joinpbx->j_updatebridge);
4208 /* we send a retrieve to that endpoint */
4209 // mixer will update the hold-state of the join and send it to the endpoints is changes
4211 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4217 /* check if we have an external call
4218 * this is used to check for encryption ability
4220 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
4222 struct join_relation *relation;
4224 class JoinPBX *joinpbx;
4225 class Endpoint *epoint;
4227 /* some paranoia check */
4228 if (!ea_endpoint->ep_portlist) {
4229 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4230 *errstr = "No Call";
4233 if (!e_ext.number[0]) {
4234 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4235 *errstr = "No Call";
4239 /* check if we have a join with 2 parties */
4240 join = find_join_id(ea_endpoint->ep_join_id);
4242 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
4243 *errstr = "No Call";
4246 if (join->j_type != JOIN_TYPE_PBX) {
4247 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4248 *errstr = "No PBX Call";
4251 joinpbx = (class JoinPBX *)join;
4252 relation = joinpbx->j_relation;
4254 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4255 *errstr = "No Call";
4258 if (!relation->next) {
4259 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4260 *errstr = "No Call";
4263 if (relation->next->next) {
4264 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4265 *errstr = "Err: Conference";
4268 if (relation->epoint_id == ea_endpoint->ep_serial) {
4269 relation = relation->next;
4270 if (relation->epoint_id == ea_endpoint->ep_serial) {
4271 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4272 *errstr = "Software Error";
4277 /* check remote port for external call */
4278 epoint = find_epoint_id(relation->epoint_id);
4280 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4281 *errstr = "No Call";
4284 if (!epoint->ep_portlist) {
4285 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4286 *errstr = "No Call";
4289 *port = find_port_id(epoint->ep_portlist->port_id);
4291 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4292 *errstr = "No Call";
4295 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4296 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4297 *errstr = "No Ext Call";
4300 if ((*port)->p_state != PORT_STATE_CONNECT) {
4301 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4302 *errstr = "No Ext Connect";
4308 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4310 const char *logtext = "unknown";
4313 switch(message_type) {
4315 trace_header("SETUP", dir);
4316 if (dir == DIRECTION_OUT)
4317 add_trace("to", NULL, "CH(%lu)", port_id);
4318 if (dir == DIRECTION_IN)
4319 add_trace("from", NULL, "CH(%lu)", port_id);
4320 if (param->setup.callerinfo.extension[0])
4321 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4322 if (param->setup.callerinfo.interface[0])
4323 add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
4324 if (param->setup.dialinginfo.interfaces[0])
4325 add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
4326 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4327 switch(param->setup.callerinfo.present) {
4328 case INFO_PRESENT_RESTRICTED:
4329 add_trace("caller id", "present", "restricted");
4331 case INFO_PRESENT_ALLOWED:
4332 add_trace("caller id", "present", "allowed");
4335 add_trace("caller id", "present", "not available");
4337 if (param->setup.callerinfo.ntype2) {
4338 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4339 switch(param->setup.callerinfo.present) {
4340 case INFO_PRESENT_RESTRICTED:
4341 add_trace("caller id2", "present", "restricted");
4343 case INFO_PRESENT_ALLOWED:
4344 add_trace("caller id2", "present", "allowed");
4347 add_trace("caller id2", "present", "not available");
4350 if (param->setup.redirinfo.id[0]) {
4351 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4352 switch(param->setup.redirinfo.present) {
4353 case INFO_PRESENT_RESTRICTED:
4354 add_trace("redir'ing", "present", "restricted");
4356 case INFO_PRESENT_ALLOWED:
4357 add_trace("redir'ing", "present", "allowed");
4360 add_trace("redir'ing", "present", "not available");
4363 if (param->setup.dialinginfo.id[0])
4364 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4365 if (param->setup.dialinginfo.keypad[0])
4366 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4367 if (param->setup.dialinginfo.display[0])
4368 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4369 if (param->setup.dialinginfo.sending_complete)
4370 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4374 case MESSAGE_OVERLAP:
4375 trace_header("SETUP ACKNOWLEDGE", dir);
4376 if (dir == DIRECTION_OUT)
4377 add_trace("to", NULL, "CH(%lu)", port_id);
4378 if (dir == DIRECTION_IN)
4379 add_trace("from", NULL, "CH(%lu)", port_id);
4383 case MESSAGE_PROCEEDING:
4384 trace_header("PROCEEDING", dir);
4385 if (dir == DIRECTION_OUT)
4386 add_trace("to", NULL, "CH(%lu)", port_id);
4387 if (dir == DIRECTION_IN)
4388 add_trace("from", NULL, "CH(%lu)", port_id);
4392 case MESSAGE_ALERTING:
4393 trace_header("ALERTING", dir);
4394 if (dir == DIRECTION_OUT)
4395 add_trace("to", NULL, "CH(%lu)", port_id);
4396 if (dir == DIRECTION_IN)
4397 add_trace("from", NULL, "CH(%lu)", port_id);
4401 case MESSAGE_CONNECT:
4402 trace_header("CONNECT", dir);
4403 if (dir == DIRECTION_OUT)
4404 add_trace("to", NULL, "CH(%lu)", port_id);
4405 if (dir == DIRECTION_IN)
4406 add_trace("from", NULL, "CH(%lu)", port_id);
4407 if (param->connectinfo.extension[0])
4408 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4409 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4410 switch(param->connectinfo.present) {
4411 case INFO_PRESENT_RESTRICTED:
4412 add_trace("connect id", "present", "restricted");
4414 case INFO_PRESENT_ALLOWED:
4415 add_trace("connect id", "present", "allowed");
4418 add_trace("connect id", "present", "not available");
4420 if (param->connectinfo.display[0])
4421 add_trace("display", NULL, "%s", param->connectinfo.display);
4425 case MESSAGE_DISCONNECT:
4426 case MESSAGE_RELEASE:
4427 if (message_type == MESSAGE_DISCONNECT)
4428 trace_header("DISCONNECT", dir);
4430 trace_header("RELEASE", dir);
4431 if (dir == DIRECTION_OUT)
4432 add_trace("to", NULL, "CH(%lu)", port_id);
4433 if (dir == DIRECTION_IN)
4434 add_trace("from", NULL, "CH(%lu)", port_id);
4435 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4436 switch(param->disconnectinfo.location) {
4438 add_trace("cause", "location", "0-User");
4440 case LOCATION_PRIVATE_LOCAL:
4441 add_trace("cause", "location", "1-Local-PBX");
4443 case LOCATION_PUBLIC_LOCAL:
4444 add_trace("cause", "location", "2-Local-Exchange");
4446 case LOCATION_TRANSIT:
4447 add_trace("cause", "location", "3-Transit");
4449 case LOCATION_PUBLIC_REMOTE:
4450 add_trace("cause", "location", "4-Remote-Exchange");
4452 case LOCATION_PRIVATE_REMOTE:
4453 add_trace("cause", "location", "5-Remote-PBX");
4455 case LOCATION_INTERNATIONAL:
4456 add_trace("cause", "location", "7-International-Exchange");
4458 case LOCATION_BEYOND:
4459 add_trace("cause", "location", "10-Beyond-Interworking");
4462 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4464 if (param->disconnectinfo.display[0])
4465 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4469 case MESSAGE_NOTIFY:
4470 switch(param->notifyinfo.notify) {
4475 logtext = "USER_SUSPENDED";
4478 logtext = "BEARER_SERVICE_CHANGED";
4481 logtext = "USER_RESUMED";
4484 logtext = "CONFERENCE_ESTABLISHED";
4487 logtext = "CONFERENCE_DISCONNECTED";
4490 logtext = "OTHER_PARTY_ADDED";
4493 logtext = "ISOLATED";
4496 logtext = "REATTACHED";
4499 logtext = "OTHER_PARTY_ISOLATED";
4502 logtext = "OTHER_PARTY_REATTACHED";
4505 logtext = "OTHER_PARTY_SPLIT";
4508 logtext = "OTHER_PARTY_DISCONNECTED";
4511 logtext = "CONFERENCE_FLOATING";
4514 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4517 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4520 logtext = "CALL_IS_A_WAITING_CALL";
4523 logtext = "DIVERSION_ACTIVATED";
4526 logtext = "RESERVED_CT_1";
4529 logtext = "RESERVED_CT_2";
4532 logtext = "REVERSE_CHARGING";
4535 logtext = "REMOTE_HOLD";
4538 logtext = "REMOTE_RETRIEVAL";
4541 logtext = "CALL_IS_DIVERTING";
4544 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4548 trace_header("NOTIFY", dir);
4549 if (dir == DIRECTION_OUT)
4550 add_trace("to", NULL, "CH(%lu)", port_id);
4551 if (dir == DIRECTION_IN)
4552 add_trace("from", NULL, "CH(%lu)", port_id);
4553 if (param->notifyinfo.notify)
4554 add_trace("indicator", NULL, "%s", logtext);
4555 if (param->notifyinfo.id[0]) {
4556 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4557 switch(param->notifyinfo.present) {
4558 case INFO_PRESENT_RESTRICTED:
4559 add_trace("redir'on", "present", "restricted");
4561 case INFO_PRESENT_ALLOWED:
4562 add_trace("redir'on", "present", "allowed");
4565 add_trace("redir'on", "present", "not available");
4568 if (param->notifyinfo.display[0])
4569 add_trace("display", NULL, "%s", param->notifyinfo.display);
4573 case MESSAGE_PROGRESS:
4574 switch(param->progressinfo.progress) {
4576 logtext = "Call is not end to end ISDN";
4579 logtext = "Destination address is non-ISDN";
4582 logtext = "Origination address is non-ISDN";
4585 logtext = "Call has returned to the ISDN";
4588 logtext = "In-band info or pattern available";
4591 SPRINT(buffer, "%d", param->progressinfo.progress);
4595 trace_header("PROGRESS", dir);
4596 if (dir == DIRECTION_OUT)
4597 add_trace("to", NULL, "CH(%lu)", port_id);
4598 if (dir == DIRECTION_IN)
4599 add_trace("from", NULL, "CH(%lu)", port_id);
4600 add_trace("indicator", NULL, "%s", logtext);
4601 switch(param->progressinfo.location) {
4603 add_trace("cause", "location", "0-User");
4605 case LOCATION_PRIVATE_LOCAL:
4606 add_trace("cause", "location", "1-Local-PBX");
4608 case LOCATION_PUBLIC_LOCAL:
4609 add_trace("cause", "location", "2-Local-Exchange");
4611 case LOCATION_TRANSIT:
4612 add_trace("cause", "location", "3-Transit");
4614 case LOCATION_PUBLIC_REMOTE:
4615 add_trace("cause", "location", "4-Remote-Exchange");
4617 case LOCATION_PRIVATE_REMOTE:
4618 add_trace("cause", "location", "5-Remote-PBX");
4620 case LOCATION_INTERNATIONAL:
4621 add_trace("cause", "location", "7-International-Exchange");
4623 case LOCATION_BEYOND:
4624 add_trace("cause", "location", "10-Beyond-Interworking");
4627 add_trace("cause", "location", "%d", param->progressinfo.location);
4632 case MESSAGE_INFORMATION:
4633 trace_header("INFORMATION", dir);
4634 if (dir == DIRECTION_OUT)
4635 add_trace("to", NULL, "CH(%lu)", port_id);
4636 if (dir == DIRECTION_IN)
4637 add_trace("from", NULL, "CH(%lu)", port_id);
4638 if (param->information.id[0])
4639 add_trace("dialing", NULL, "%s", param->information.id);
4640 if (param->information.display[0])
4641 add_trace("display", NULL, "%s", param->information.display);
4642 if (param->information.sending_complete)
4643 add_trace("complete", NULL, "true", param->information.sending_complete);
4647 case MESSAGE_FACILITY:
4648 trace_header("FACILITY", dir);
4649 if (dir == DIRECTION_OUT)
4650 add_trace("to", NULL, "CH(%lu)", port_id);
4651 if (dir == DIRECTION_IN)
4652 add_trace("from", NULL, "CH(%lu)", port_id);
4657 trace_header("TONE", dir);
4658 if (dir == DIRECTION_OUT)
4659 add_trace("to", NULL, "CH(%lu)", port_id);
4660 if (dir == DIRECTION_IN)
4661 add_trace("from", NULL, "CH(%lu)", port_id);
4662 if (param->tone.name[0]) {
4663 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4664 add_trace("name", NULL, "%s", param->tone.name);
4666 add_trace("off", NULL, NULL);
4670 case MESSAGE_SUSPEND:
4671 case MESSAGE_RESUME:
4672 if (message_type == MESSAGE_SUSPEND)
4673 trace_header("SUSPEND", dir);
4675 trace_header("RESUME", dir);
4676 if (dir == DIRECTION_OUT)
4677 add_trace("to", NULL, "CH(%lu)", port_id);
4678 if (dir == DIRECTION_IN)
4679 add_trace("from", NULL, "CH(%lu)", port_id);
4680 if (param->parkinfo.len)
4681 add_trace("length", NULL, "%d", param->parkinfo.len);
4686 case MESSAGE_BCHANNEL:
4687 trace_header("BCHANNEL", dir);
4688 switch(param->bchannel.type) {
4689 case BCHANNEL_REQUEST:
4690 add_trace("type", NULL, "request");
4692 case BCHANNEL_ASSIGN:
4693 add_trace("type", NULL, "assign");
4695 case BCHANNEL_ASSIGN_ACK:
4696 add_trace("type", NULL, "assign_ack");
4698 case BCHANNEL_REMOVE:
4699 add_trace("type", NULL, "remove");
4701 case BCHANNEL_REMOVE_ACK:
4702 add_trace("type", NULL, "remove_ack");
4705 if (param->bchannel.addr)
4706 add_trace("address", NULL, "%x", param->bchannel.addr);
4712 if (param->threepty.begin)
4713 trace_header("Begin3PTY", dir);
4714 if (param->threepty.end)
4715 trace_header("End3PTY", dir);
4716 if (param->threepty.invoke)
4717 add_trace("action", NULL, "invoke");
4718 if (param->threepty.result)
4719 add_trace("action", NULL, "result");
4720 if (param->threepty.error)
4721 add_trace("action", NULL, "error");
4722 add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id);
4726 case MESSAGE_TRANSFER:
4727 trace_header("TRANSFER", dir);
4731 case MESSAGE_DISABLE_DEJITTER:
4732 trace_header("DISBALE_DEJITTER", dir);
4734 add_trace("queue", NULL, "%d", param->queue);
4739 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4743 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4745 struct lcr_msg *message;
4749 if (!portlist->port_id)
4752 if (!e_connectedmode) {
4753 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4754 message->param.disconnectinfo.cause = cause;
4755 message->param.disconnectinfo.location = location;
4757 SCPY(message->param.disconnectinfo.display, display);
4759 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4761 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4763 SCPY(message->param.notifyinfo.display, display);
4765 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4767 message_put(message);
4768 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);