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)
530 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) enable VoOTP.\n", ea_endpoint->ep_serial);
536 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) disable VoOTP.\n", ea_endpoint->ep_serial);
543 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
547 /* crypt key-exchange */
549 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
555 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
560 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
565 /* set tone pattern for port */
566 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
568 struct lcr_msg *message;
573 /* store for suspended processes */
577 if (e_join_pattern /* pattern are provided */
578 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
579 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
580 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
581 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
582 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
583 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
584 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
585 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
586 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
587 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
588 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
589 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
594 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
595 SCPY(message->param.tone.dir, e_ext.tones_dir);
596 SCPY(message->param.tone.name, tone);
597 message_put(message);
598 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
600 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
606 /* outgoing setup to port(s)
607 * ports will be created and a setup is sent if everything is ok. otherwhise
608 * the endpoint is destroyed.
610 void EndpointAppPBX::out_setup(int cfnr)
612 struct dialing_info dialinginfo;
614 struct port_list *portlist;
615 struct lcr_msg *message;
617 int cause = CAUSE_RESSOURCEUNAVAIL;
620 struct interface *interface;
622 struct mISDNport *mISDNport;
626 class EndpointAppPBX *atemp;
627 // char allowed_ports[256];
629 char ifname[sizeof(e_ext.interfaces)],
633 struct port_settings port_settings;
637 struct admin_list *admin;
639 int mode = B_MODE_TRANSPARENT;
641 /* set bchannel mode */
642 mode = e_capainfo.source_mode;
644 /* create settings for creating port */
645 memset(&port_settings, 0, sizeof(port_settings));
647 SCPY(port_settings.tones_dir, e_ext.tones_dir);
649 SCPY(port_settings.tones_dir, options.tones_dir);
650 port_settings.no_seconds = e_ext.no_seconds;
652 /* 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 */
654 /* check what dialinginfo.itype we got */
655 switch(e_dialinginfo.itype) {
656 /* *********************** call to extension or vbox */
657 case INFO_ITYPE_ISDN_EXTENSION:
658 /* check if we deny incoming calls when we use an extension */
659 if (e_ext.noknocking) {
660 atemp = apppbx_first;
663 if (!strcmp(atemp->e_ext.number, e_ext.number))
668 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
669 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
670 return; /* must exit here */
673 /* FALL THROUGH !!!! */
674 case INFO_ITYPE_VBOX:
675 /* get dialed extension's info */
676 // SCPY(exten, e_dialinginfo.id);
677 // if (strchr(exten, ','))
678 // *strchr(exten, ',') = '\0';
679 // if (!read_extension(&e_ext, exten))
680 if (!read_extension(&e_ext, e_dialinginfo.id)) {
681 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
682 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
683 return; /* must exit here */
685 e_dialinginfo.sending_complete = 1;
687 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
688 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
693 /* string from unconditional call forward (cfu) */
696 /* present to forwarded party */
697 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
698 e_callerinfo.present = INFO_PRESENT_ALLOWED;
700 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
704 /* string from busy call forward (cfb) */
707 class EndpointAppPBX *checkapp = apppbx_first;
709 if (checkapp != this) { /* any other endpoint except our own */
710 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
711 /* present to forwarded party */
712 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
713 e_callerinfo.present = INFO_PRESENT_ALLOWED;
715 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
719 checkapp = checkapp->next;
723 /* string from no-response call forward (cfnr) */
726 /* when cfnr is done, out_setup() will setup the call */
728 /* present to forwarded party */
729 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
730 e_callerinfo.present = INFO_PRESENT_ALLOWED;
734 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
735 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
736 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
737 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);
741 /* call to all internal interfaces */
742 p = e_ext.interfaces;
743 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
747 while(*p!=',' && *p!='\0')
752 /* search interface */
753 interface = hunt_interface(ifname);
755 trace_header("INTERFACE (not found)", DIRECTION_NONE);
756 add_trace("interface", NULL, "%s", ifname);
760 /* found interface */
761 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
762 if (interface->remote) {
765 if (admin->remote_name[0] && !strcmp(admin->remote_name, interface->remote_app))
770 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
771 add_trace("application", NULL, "%s", interface->remote_app);
775 SPRINT(portname, "%s-%d-out", interface->name, 0);
776 port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface, admin->sock);
777 earlyb = (interface->is_earlyb == IS_YES);
780 if (interface->gsm_bs) {
781 SPRINT(portname, "%s-%d-out", interface->name, 0);
782 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
783 earlyb = (interface->is_earlyb == IS_YES);
787 if (interface->gsm_ms) {
788 SPRINT(portname, "%s-%d-out", interface->name, 0);
789 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
790 earlyb = (interface->is_earlyb == IS_YES);
794 if (interface->sip) {
795 SPRINT(portname, "%s-%d-out", interface->name, 0);
796 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
797 earlyb = (interface->is_earlyb == IS_YES);
802 /* hunt for mISDNport and create Port */
803 mISDNport = hunt_port(ifname, &channel);
805 trace_header("INTERFACE (busy)", DIRECTION_NONE);
806 add_trace("interface", NULL, "%s", ifname);
811 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
814 port = ss5_hunt_line(mISDNport);
817 #ifdef ISDN_P_FXS_POTS
819 port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
822 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);
823 earlyb = mISDNport->earlyb;
825 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
826 add_trace("interface", NULL, "%s", ifname);
832 FATAL("Failed to create Port instance\n");
833 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
834 memset(&dialinginfo, 0, sizeof(dialinginfo));
835 SCPY(dialinginfo.id, e_dialinginfo.id);
836 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
837 dialinginfo.ntype = e_dialinginfo.ntype;
838 /* create port_list relation */
839 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
841 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
843 goto check_anycall_intern;
846 if (e_callerinfo.id[0] && e_ext.display_name) {
847 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
849 SCPY(e_callerinfo.name, dirname);
851 // dss1 = (class Pdss1 *)port;
853 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
854 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
855 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
856 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
857 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
858 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
859 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
860 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
861 //terminal if (e_dialinginfo.id)
862 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
863 /* handle restricted caller ids */
864 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);
865 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);
866 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);
867 /* display callerid if desired for extension */
868 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));
869 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
870 /* use cnip, if enabld */
871 // if (!e_ext.centrex)
872 // message->param.setup.callerinfo.name[0] = '\0';
873 /* screen clip if prefix is required */
874 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
875 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
876 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
877 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
879 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
880 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
881 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
882 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
884 /* use internal caller id */
885 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
886 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
887 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
888 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
890 message_put(message);
891 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
895 /* string from parallel call forward (cfp) */
898 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
899 e_callerinfo.present = INFO_PRESENT_ALLOWED;
900 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
904 vbox_only: /* entry point for answering machine only */
905 cfu_only: /* entry point for cfu */
906 cfb_only: /* entry point for cfb */
907 cfnr_only: /* entry point for cfnr */
908 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
912 /* only if vbox should be dialed, and terminal is given */
913 if (!strcmp(p, "vbox") && e_ext.number[0]) {
914 /* go to the end of p */
917 /* answering vbox call */
918 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
920 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
921 FATAL("No memory for VBOX Port instance\n");
922 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
923 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
926 while(*p!=',' && *p!='\0')
931 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
933 /* hunt for mISDNport and create Port */
934 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
936 /* creating EXTERNAL port*/
937 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
940 port = ss5_hunt_line(mISDNport);
943 #ifdef ISDN_P_FXS_POTS
945 port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
948 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);
950 FATAL("No memory for Port instance\n");
951 earlyb = mISDNport->earlyb;
956 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
957 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
962 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
963 goto check_anycall_intern;
965 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
966 memset(&dialinginfo, 0, sizeof(dialinginfo));
967 SCPY(dialinginfo.id, cfp);
968 dialinginfo.itype = INFO_ITYPE_ISDN;
969 dialinginfo.ntype = e_dialinginfo.ntype;
970 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
972 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
974 goto check_anycall_intern;
976 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
977 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
978 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
979 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
980 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
981 /* if clip is hidden */
982 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
983 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
984 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
985 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
986 message->param.setup.callerinfo.present = e_ext.callerid_present;
987 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
989 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
990 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
991 //terminal if (e_dialinginfo.id)
992 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
993 /* handle restricted caller ids */
994 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);
995 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);
996 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);
997 /* display callerid if desired for extension */
998 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));
999 message_put(message);
1000 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1004 check_anycall_intern:
1005 /* now we have all ports created */
1007 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1009 if (!ea_endpoint->ep_join_id)
1011 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1012 return; /* must exit here */
1016 /* *********************** external call */
1018 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1019 /* call to extenal interfaces */
1020 if (e_dialinginfo.keypad[0])
1021 number_p = e_dialinginfo.keypad;
1023 number_p = e_dialinginfo.id;
1026 while(*number_p!=',' && *number_p!='\0')
1027 SCCAT(number, *number_p++);
1028 if (*number_p == ',')
1032 ifname_p = e_dialinginfo.interfaces;
1033 if (*ifname_p == '+')
1038 while(*ifname_p!=',' && *ifname_p!='\0')
1039 SCCAT(ifname, *ifname_p++);
1040 if (*ifname_p == ',')
1042 /* found interface name */
1044 /* search interface */
1045 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, ifname[0]?ifname:"any interface");
1046 interface = hunt_interface(ifname[0]?ifname:NULL);
1048 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1049 add_trace("interface", NULL, "%s", ifname);
1053 /* found interface */
1054 if (interface->remote) {
1055 admin = admin_first;
1057 if (admin->remote_name[0] && !strcmp(admin->remote_name, interface->remote_app))
1059 admin = admin->next;
1062 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1063 add_trace("application", NULL, "%s", interface->remote_app);
1067 SPRINT(portname, "%s-%d-out", interface->name, 0);
1068 port = new Premote(PORT_TYPE_REMOTE_OUT, portname, &port_settings, interface, admin->sock);
1069 earlyb = (interface->is_earlyb == IS_YES);
1072 if (interface->gsm_bs) {
1073 SPRINT(portname, "%s-%d-out", interface->name, 0);
1074 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1075 earlyb = (interface->is_earlyb == IS_YES);
1079 if (interface->gsm_ms) {
1080 SPRINT(portname, "%s-%d-out", interface->name, 0);
1081 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1082 earlyb = (interface->is_earlyb == IS_YES);
1086 if (interface->sip) {
1087 SPRINT(portname, "%s-%d-out", interface->name, 0);
1088 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1089 earlyb = (interface->is_earlyb == IS_YES);
1094 /* hunt for mISDNport and create Port */
1095 mISDNport = hunt_port(ifname[0]?ifname:NULL, &channel);
1097 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1098 add_trace("interface", NULL, "%s", ifname[0]?ifname:"any interface");
1102 /* creating EXTERNAL port*/
1103 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1107 port = ss5_hunt_line(mISDNport);
1110 #ifdef ISDN_P_FXS_POTS
1111 if (mISDNport->pots)
1112 port = new Pfxs(PORT_TYPE_POTS_FXS_OUT, mISDNport, portname, &port_settings, mISDNport->ifport->interface, mode);
1115 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);
1116 earlyb = mISDNport->earlyb;
1118 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
1119 add_trace("interface", NULL, "%s", ifname);
1125 FATAL("No memory for Port instance\n");
1126 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1127 memset(&dialinginfo, 0, sizeof(dialinginfo));
1128 if (e_dialinginfo.keypad[0])
1129 SCPY(dialinginfo.keypad, number);
1131 SCPY(dialinginfo.id, number);
1132 dialinginfo.itype = INFO_ITYPE_ISDN;
1133 dialinginfo.ntype = e_dialinginfo.ntype;
1134 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1135 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1137 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1141 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1142 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1143 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1144 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1145 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1146 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1147 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1148 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1149 //terminal if (e_dialinginfo.id)
1150 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1151 /* handle restricted caller ids */
1152 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);
1153 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);
1154 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);
1155 /* display callerid if desired for extension */
1156 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));
1157 message_put(message);
1158 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1161 /* found an interface
1162 * continue only if + is given, so every interface is calles parallel */
1163 if (e_dialinginfo.interfaces[0] != '+')
1165 } while (*ifname_p);
1168 /* now we have all ports created */
1170 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1172 if (!ea_endpoint->ep_join_id)
1174 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1175 return; /* must exit here */
1182 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1184 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1186 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1189 unsched_timer(&ea->e_redial_timeout);
1190 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1191 ea->e_multipoint_cause = 0;
1192 ea->e_multipoint_location = 0;
1193 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1194 ea->e_join_pattern = 0;
1195 ea->process_dialing(1);
1196 /* we must exit, because our endpoint might be gone */
1201 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1203 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1205 if (!ea->e_action) {
1206 unsched_timer(&ea->e_redial_timeout);
1207 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1208 ea->process_dialing(0);
1209 /* we must exit, because our endpoint might be gone */
1215 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1217 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1219 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1221 ea->new_state(EPOINT_STATE_OUT_SETUP);
1222 /* call special setup routine */
1228 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1230 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1232 /* leave power dialing on */
1233 ea->e_powerdial_on = 1;
1234 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1237 ea->e_ruleset = ruleset_main;
1239 ea->e_rule = ea->e_ruleset->rule_first;
1240 ea->e_action = NULL;
1241 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1242 ea->process_dialing(0);
1247 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1249 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1250 struct port_list *portlist;
1251 struct lcr_msg *message;
1253 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1255 /* release all ports */
1256 while((portlist = ea->ea_endpoint->ep_portlist)) {
1257 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1258 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1259 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1260 message_put(message);
1261 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1262 ea->ea_endpoint->free_portlist(portlist);
1265 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1266 message->param.audiopath = 0;
1267 message_put(message);
1268 /* indicate no patterns */
1269 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1270 message_put(message);
1271 /* set setup state, since we have no response from the new join */
1272 ea->new_state(EPOINT_STATE_OUT_SETUP);
1277 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1279 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1281 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);
1287 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1289 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1291 if (ea->e_state == EPOINT_STATE_IDLE) {
1292 /* epoint is idle, check callback */
1293 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1294 ea->new_state(EPOINT_STATE_OUT_SETUP);
1301 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1303 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1305 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1306 struct port_list *portlist;
1308 ea->e_ruleset = ruleset_main;
1310 ea->e_rule = ea->e_ruleset->rule_first;
1311 ea->e_action = NULL;
1312 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1313 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1315 ea->e_connectedmode = 0;
1317 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1318 portlist = ea->ea_endpoint->ep_portlist;
1320 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1321 ea->set_tone(portlist, "cause_10");
1328 /* doing a hookflash */
1329 void EndpointAppPBX::hookflash(void)
1334 /* be sure that we are active */
1336 e_tx_state = NOTIFY_STATE_ACTIVE;
1338 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1340 if (ea_endpoint->ep_use > 1) {
1341 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1344 /* dialtone after pressing the hash key */
1345 process_hangup(e_join_cause, e_join_location);
1346 e_multipoint_cause = 0;
1347 e_multipoint_location = 0;
1348 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1350 port->set_echotest(0);
1352 if (ea_endpoint->ep_join_id) {
1353 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1355 e_ruleset = ruleset_main;
1357 e_rule = e_ruleset->rule_first;
1359 new_state(EPOINT_STATE_IN_OVERLAP);
1360 e_connectedmode = 1;
1361 SCPY(e_dialinginfo.id, e_ext.prefix);
1362 e_extdialing = e_dialinginfo.id;
1364 if (e_dialinginfo.id[0]) {
1365 set_tone(ea_endpoint->ep_portlist, "dialing");
1368 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1376 /* messages from port
1378 /* port MESSAGE_SETUP */
1379 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1381 struct lcr_msg *message;
1383 int writeext; /* flags need to write extension after modification */
1386 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1388 portlist->port_type = param->setup.port_type;
1389 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1390 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1391 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1392 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1393 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
1395 /* convert (inter-)national number type */
1396 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1397 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1399 // e_dtmf = param->setup.dtmf;
1400 /* screen incoming caller id */
1401 if (e_callerinfo.interface[0]) {
1402 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface);
1403 if (e_callerinfo.id2[0]) do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
1404 if (e_redirinfo.id[0]) do_screen(0, e_redirinfo.id, sizeof(e_redirinfo.id), &e_redirinfo.ntype, &e_redirinfo.present, e_callerinfo.interface);
1407 /* process extension */
1408 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1409 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1410 /* port makes call from extension */
1411 SCPY(e_callerinfo.extension, e_callerinfo.id);
1412 SCPY(e_ext.number, e_callerinfo.extension);
1413 SCPY(e_extension_interface, e_callerinfo.interface);
1415 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1418 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1419 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1421 /* get extension's info about caller */
1422 if (!read_extension(&e_ext, e_ext.number)) {
1423 /* extension doesn't exist */
1424 trace_header("EXTENSION (not created)", DIRECTION_IN);
1425 add_trace("extension", NULL, "%s", e_ext.number);
1427 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1428 new_state(EPOINT_STATE_OUT_DISCONNECT);
1429 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1430 e_ext.number[0] = '\0'; /* no terminal */
1435 /* put prefix (next) in front of e_dialinginfo.id */
1436 if (e_ext.next[0]) {
1437 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1438 SCPY(e_dialinginfo.id, buffer);
1439 e_ext.next[0] = '\0';
1441 } else if (e_ext.prefix[0]) {
1442 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1443 SCPY(e_dialinginfo.id, buffer);
1446 /* screen caller id by extension's config */
1447 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1449 SCPY(e_callerinfo.name, e_ext.name);
1450 /* use caller id (or if exist: id_next_call) for this call */
1451 if (e_ext.id_next_call_present >= 0) {
1452 SCPY(e_callerinfo.id, e_ext.id_next_call);
1453 /* if we restrict the pesentation */
1454 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1455 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1456 else e_callerinfo.present = e_ext.id_next_call_present;
1457 e_callerinfo.ntype = e_ext.id_next_call_type;
1458 e_ext.id_next_call_present = -1;
1461 SCPY(e_callerinfo.id, e_ext.callerid);
1462 /* if we restrict the pesentation */
1463 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1464 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1465 else e_callerinfo.present = e_ext.callerid_present;
1466 e_callerinfo.ntype = e_ext.callerid_type;
1468 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1470 /* extension is written */
1472 write_extension(&e_ext, e_ext.number);
1474 /* set volume of rx and tx */
1475 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1476 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1477 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1478 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1479 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1480 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1481 message_put(message);
1484 /* start recording if enabled */
1485 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1486 /* check if we are a terminal */
1487 if (e_ext.number[0] == '\0')
1488 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1490 port = find_port_id(portlist->port_id);
1492 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1496 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1497 /* no terminal identification */
1498 e_ext.number[0] = '\0';
1499 e_extension_interface[0] = '\0';
1500 memset(&e_ext, 0, sizeof(e_ext));
1501 e_ext.rights = 4; /* right to dial internat */
1505 e_ruleset = ruleset_main;
1507 e_rule = e_ruleset->rule_first;
1509 e_extdialing = e_dialinginfo.id;
1510 new_state(EPOINT_STATE_IN_SETUP);
1511 if (e_dialinginfo.id[0]) {
1512 set_tone(portlist, "dialing");
1514 if (e_ext.number[0])
1515 set_tone(portlist, "dialpbx");
1517 set_tone(portlist, "dialtone");
1520 if (e_state == EPOINT_STATE_IN_SETUP) {
1521 /* request MORE info, if not already at higher state */
1522 new_state(EPOINT_STATE_IN_OVERLAP);
1523 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1524 message_put(message);
1525 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1529 /* port MESSAGE_INFORMATION */
1530 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1532 struct lcr_msg *message;
1534 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1536 /* ignore information message without digit information */
1537 if (!param->information.id[0])
1542 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1544 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1549 /* if vbox_play is done, the information are just used as they come */
1551 if (e_action->index == ACTION_VBOX_PLAY) {
1552 /* concat dialing string */
1553 SCAT(e_dialinginfo.id, param->information.id);
1558 /* keypad when disconnect but in connected mode */
1559 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1560 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1561 /* processing keypad function */
1562 if (param->information.id[0] == '0') {
1568 /* keypad when connected */
1569 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1570 if (e_enablekeypad) {
1571 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1572 memcpy(&message->param, param, sizeof(union parameter));
1573 message_put(message);
1577 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1578 /* processing keypad function */
1579 if (param->information.id[0] == '0') {
1582 if (param->information.id[0])
1583 keypad_function(param->information.id[0]);
1585 if (e_ext.number[0])
1586 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1588 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1593 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1594 if (e_ext.number[0])
1595 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1597 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1601 if (!param->information.id[0])
1603 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1604 set_tone(portlist, "dialing");
1607 if (e_action->index==ACTION_OUTDIAL
1608 || e_action->index==ACTION_EXTERNAL) {
1610 set_tone(portlist, "dialing");
1611 else if (!e_extdialing[0])
1612 set_tone(portlist, "dialing");
1614 /* concat dialing string */
1615 SCAT(e_dialinginfo.id, param->information.id);
1619 /* port MESSAGE_DTMF */
1620 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1623 struct lcr_msg *message;
1627 /* only if dtmf detection is enabled */
1629 trace_header("DTMF (disabled)", DIRECTION_IN);
1633 trace_header("DTMF", DIRECTION_IN);
1634 add_trace("digit", NULL, "%c", param->dtmf);
1638 NOTE: vbox is now handled due to overlap state
1639 /* if vbox_play is done, the dtmf digits are just used as they come */
1641 if (e_action->index == ACTION_VBOX_PLAY) {
1642 /* concat dialing string */
1643 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1644 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1645 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1648 /* continue to process *X# sequences */
1652 /* check for *X# sequence */
1653 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1654 if (e_enablekeypad) {
1655 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1656 memcpy(&message->param, param, sizeof(union parameter));
1657 message_put(message);
1660 if (e_dtmf_time+3 < now) {
1661 /* the last digit was too far in the past to be a sequence */
1662 if (param->dtmf == '*')
1663 /* only start is allowed in the sequence */
1668 /* we have a sequence of digits, see what we got */
1669 if (param->dtmf == '*')
1671 else if (param->dtmf>='0' && param->dtmf<='9') {
1672 /* we need to have a star before we receive the digit of the sequence */
1673 if (e_dtmf_last == '*')
1674 e_dtmf_last = param->dtmf;
1675 } else if (param->dtmf == '#') {
1677 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1678 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1679 if (e_dtmf_last == '0') {
1683 /* processing keypad function */
1685 keypad_function(e_dtmf_last);
1691 /* set last time of dtmf */
1696 /* check for ## hookflash during dialing */
1698 if (e_action->index==ACTION_PASSWORD
1699 || e_action->index==ACTION_PASSWORD_WRITE)
1701 if (param->dtmf=='#') { /* current digit is '#' */
1702 if (e_state==EPOINT_STATE_IN_DISCONNECT
1703 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1717 /* dialing using dtmf digit */
1718 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1719 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1720 set_tone(portlist, "dialing");
1722 /* concat dialing string */
1723 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1724 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1725 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1731 /* port MESSAGE_CRYPT */
1732 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1735 /* send crypt response to cryptman */
1736 if (param->crypt.type == CR_MESSAGE_IND)
1737 cryptman_msg2man(param->crypt.data, param->crypt.len);
1739 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1743 /* port MESSAGE_OVERLAP */
1744 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1746 struct lcr_msg *message;
1748 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1750 /* signal to call tool */
1751 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1753 if (e_dialing_queue[0] && portlist) {
1754 /* send what we have not dialed yet, because we had no setup complete */
1755 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1756 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1757 SCPY(message->param.information.id, e_dialing_queue);
1758 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1759 message_put(message);
1760 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1761 e_dialing_queue[0] = '\0';
1763 /* check if pattern is available */
1764 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1765 /* indicate patterns */
1766 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1767 message_put(message);
1769 /* connect audio, if not already */
1770 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1771 message->param.audiopath = 1;
1772 message_put(message);
1774 /* indicate no patterns */
1775 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1776 message_put(message);
1778 /* disconnect audio, if not already */
1779 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1780 message->param.audiopath = 0;
1781 message_put(message);
1783 new_state(EPOINT_STATE_OUT_OVERLAP);
1784 /* if we are in a join */
1785 if (ea_endpoint->ep_join_id) {
1786 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1787 memcpy(&message->param, param, sizeof(union parameter));
1788 message_put(message);
1792 /* port MESSAGE_PROCEEDING */
1793 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1795 struct lcr_msg *message;
1797 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1799 /* signal to call tool */
1800 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1802 e_state = EPOINT_STATE_OUT_PROCEEDING;
1803 /* check if pattern is availatle */
1804 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1805 /* indicate patterns */
1806 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1807 message_put(message);
1809 /* connect audio, if not already */
1810 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1811 message->param.audiopath = 1;
1812 message_put(message);
1814 /* indicate no patterns */
1815 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1816 message_put(message);
1818 /* disconnect audio, if not already */
1819 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1820 message->param.audiopath = 0;
1821 message_put(message);
1823 /* if we are in a call */
1824 if (ea_endpoint->ep_join_id) {
1825 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1826 memcpy(&message->param, param, sizeof(union parameter));
1827 message_put(message);
1831 /* port MESSAGE_ALERTING */
1832 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1834 struct lcr_msg *message;
1836 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1838 /* signal to call tool */
1839 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1842 // set_tone(portlist, "hold");
1844 new_state(EPOINT_STATE_OUT_ALERTING);
1845 /* check if pattern is available */
1846 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1847 /* indicate patterns */
1848 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1849 message_put(message);
1851 /* connect audio, if not already */
1852 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1853 message->param.audiopath = 1;
1854 message_put(message);
1856 /* indicate no patterns */
1857 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1858 message_put(message);
1860 /* disconnect audio, if not already */
1861 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1862 message->param.audiopath = 0;
1863 message_put(message);
1865 /* if we are in a call */
1866 if (ea_endpoint->ep_join_id) {
1867 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1868 memcpy(&message->param, param, sizeof(union parameter));
1869 message_put(message);
1873 /* port MESSAGE_CONNECT */
1874 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1876 struct lcr_msg *message;
1878 unsigned int port_id = portlist->port_id;
1879 struct port_list *tportlist;
1883 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1885 /* signal to call tool */
1886 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1888 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1889 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1890 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1891 tportlist = ea_endpoint->ep_portlist;
1892 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1893 tportlist = tportlist->next;
1894 if (tportlist->port_id == port_id)
1895 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1896 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1897 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1898 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1899 message_put(message);
1900 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1901 ea_endpoint->free_portlist(tportlist);
1903 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1908 if (e_callerinfo.interface[0])
1909 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface);
1911 /* screen connected name */
1913 SCPY(e_connectinfo.name, e_ext.name);
1915 /* add internal id to colp */
1916 SCPY(e_connectinfo.extension, e_ext.number);
1918 /* we store the connected port number */
1919 SCPY(e_extension_interface, e_connectinfo.interface);
1921 /* for internal and am calls, we get the extension's id */
1922 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1923 SCPY(e_connectinfo.id, e_ext.callerid);
1924 SCPY(e_connectinfo.extension, e_ext.number);
1925 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1926 e_connectinfo.ntype = e_ext.callerid_type;
1927 e_connectinfo.present = e_ext.callerid_present;
1929 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
1930 e_connectinfo.itype = INFO_ITYPE_VBOX;
1931 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1934 new_state(EPOINT_STATE_CONNECT);
1936 /* set volume of rx and tx */
1937 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1938 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1939 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1940 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1941 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1942 message_put(message);
1945 unsched_timer(&e_cfnr_timeout);
1946 unsched_timer(&e_cfnr_call_timeout);
1947 if (e_ext.number[0])
1948 e_dtmf = 1; /* allow dtmf */
1951 /* other calls with no caller id (or not available for the extension) and force colp */
1952 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
1953 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
1954 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
1955 /* external extension answered */
1956 port = find_port_id(portlist->port_id);
1958 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
1959 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1964 /* send connect to join */
1965 if (ea_endpoint->ep_join_id) {
1966 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1967 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1968 message_put(message);
1970 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1971 message->param.audiopath = 1;
1972 message_put(message);
1973 } else if (!e_adminid) {
1975 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
1976 SCPY(e_ext.number, e_cbcaller);
1977 new_state(EPOINT_STATE_IN_OVERLAP);
1978 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1980 /* get extension's info about terminal */
1981 if (!read_extension(&e_ext, e_ext.number)) {
1982 /* extension doesn't exist */
1983 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1984 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1985 new_state(EPOINT_STATE_OUT_DISCONNECT);
1986 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1990 /* put prefix in front of e_cbdialing */
1991 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
1992 SCPY(e_dialinginfo.id, buffer);
1993 e_dialinginfo.itype = INFO_ITYPE_ISDN;
1994 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1996 /* use caller id (or if exist: id_next_call) for this call */
1997 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1998 SCPY(e_callerinfo.extension, e_ext.number);
1999 if (e_ext.id_next_call_present >= 0) {
2000 SCPY(e_callerinfo.id, e_ext.id_next_call);
2001 e_callerinfo.present = e_ext.id_next_call_present;
2002 e_callerinfo.ntype = e_ext.id_next_call_type;
2003 e_ext.id_next_call_present = -1;
2004 /* extension is written */
2005 write_extension(&e_ext, e_ext.number);
2007 SCPY(e_callerinfo.id, e_ext.callerid);
2008 e_callerinfo.present = e_ext.callerid_present;
2009 e_callerinfo.ntype = e_ext.callerid_type;
2011 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2013 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2016 /* check if caller id is NOT authenticated */
2017 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2018 /* make call state to enter password */
2019 new_state(EPOINT_STATE_IN_OVERLAP);
2020 e_action = &action_password_write;
2021 unsched_timer(&e_match_timeout);
2022 e_match_to_action = NULL;
2023 e_dialinginfo.id[0] = '\0';
2024 e_extdialing = strchr(e_dialinginfo.id, '\0');
2025 schedule_timer(&e_password_timeout, 20, 0);
2028 /* incoming call (callback) */
2029 e_ruleset = ruleset_main;
2031 e_rule = e_ruleset->rule_first;
2033 e_extdialing = e_dialinginfo.id;
2034 if (e_dialinginfo.id[0]) {
2035 set_tone(portlist, "dialing");
2038 set_tone(portlist, "dialpbx");
2041 } else { /* testcall */
2042 set_tone(portlist, "hold");
2045 /* start recording if enabled, not when answering machine answers */
2046 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)) {
2047 /* check if we are a terminal */
2048 if (e_ext.number[0] == '\0')
2049 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2051 port = find_port_id(portlist->port_id);
2053 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2058 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2059 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2061 struct lcr_msg *message;
2063 unsigned int port_id = portlist->port_id;
2067 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2069 /* signal to call tool */
2070 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2072 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2073 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2074 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2079 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);
2080 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2081 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2083 /* check if we have more than one portlist relation and we just ignore the disconnect */
2084 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2085 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2086 portlist = ea_endpoint->ep_portlist;
2088 if (portlist->port_id == port_id)
2090 portlist = portlist->next;
2093 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2094 if (message_type != MESSAGE_RELEASE) {
2095 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2096 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2097 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2098 message_put(message);
2099 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2101 ea_endpoint->free_portlist(portlist);
2102 return; /* one relation removed */
2104 if (e_state == EPOINT_STATE_CONNECT) {
2105 /* use cause from port after connect */
2106 cause = param->disconnectinfo.cause;
2107 location = param->disconnectinfo.location;
2109 /* use multipoint cause if no connect yet */
2110 if (e_multipoint_cause) {
2111 cause = e_multipoint_cause;
2112 location = e_multipoint_location;
2114 cause = CAUSE_NOUSER;
2115 location = LOCATION_PRIVATE_LOCAL;
2119 unsched_timer(&e_cfnr_timeout);
2120 unsched_timer(&e_cfnr_call_timeout);
2122 /* process hangup */
2123 process_hangup(e_join_cause, e_join_location);
2124 e_multipoint_cause = 0;
2125 e_multipoint_location = 0;
2127 if (message_type == MESSAGE_DISCONNECT) {
2128 /* tone to disconnected end */
2129 SPRINT(buffer, "cause_%02x", cause);
2130 if (ea_endpoint->ep_portlist)
2131 set_tone(ea_endpoint->ep_portlist, buffer);
2133 new_state(EPOINT_STATE_IN_DISCONNECT);
2136 if (ea_endpoint->ep_join_id) {
2137 int haspatterns = 0;
2138 /* check if pattern is available */
2139 if (ea_endpoint->ep_portlist)
2140 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2141 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
2142 && message_type != MESSAGE_RELEASE) // if we release, we are done
2145 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2146 /* indicate patterns */
2147 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2148 message_put(message);
2149 /* connect audio, if not already */
2150 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2151 message->param.audiopath = 1;
2152 message_put(message);
2153 /* send disconnect */
2154 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2155 memcpy(&message->param, param, sizeof(union parameter));
2156 message_put(message);
2157 /* disable encryption if disconnected */
2158 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2161 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2165 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2168 if (message_type == MESSAGE_RELEASE)
2169 ea_endpoint->free_portlist(portlist);
2170 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2171 return; /* must exit here */
2174 /* port MESSAGE_TIMEOUT */
2175 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2179 trace_header("TIMEOUT", DIRECTION_IN);
2180 message_type = MESSAGE_DISCONNECT;
2181 switch (param->state) {
2182 case PORT_STATE_OUT_SETUP:
2183 case PORT_STATE_OUT_OVERLAP:
2184 add_trace("state", NULL, "outgoing setup/dialing");
2186 /* no user responding */
2187 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2188 return; /* must exit here */
2190 case PORT_STATE_IN_SETUP:
2191 case PORT_STATE_IN_OVERLAP:
2192 add_trace("state", NULL, "incoming setup/dialing");
2193 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2194 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2197 case PORT_STATE_OUT_PROCEEDING:
2198 add_trace("state", NULL, "outgoing proceeding");
2200 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2201 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2202 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2203 return; /* must exit here */
2205 case PORT_STATE_IN_PROCEEDING:
2206 add_trace("state", NULL, "incoming proceeding");
2207 param->disconnectinfo.cause = CAUSE_NOUSER;
2208 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2211 case PORT_STATE_OUT_ALERTING:
2212 add_trace("state", NULL, "outgoing alerting");
2214 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2215 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2216 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2217 return; /* must exit here */
2219 case PORT_STATE_CONNECT:
2220 add_trace("state", NULL, "connect");
2222 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2223 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2224 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2225 return; /* must exit here */
2227 case PORT_STATE_IN_ALERTING:
2228 add_trace("state", NULL, "incoming alerting");
2229 param->disconnectinfo.cause = CAUSE_NOANSWER;
2230 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2233 case PORT_STATE_IN_DISCONNECT:
2234 case PORT_STATE_OUT_DISCONNECT:
2235 add_trace("state", NULL, "disconnect");
2237 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2238 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2239 return; /* must exit here */
2242 param->disconnectinfo.cause = 31; /* normal unspecified */
2243 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2246 /* release call, disconnect isdn */
2248 new_state(EPOINT_STATE_OUT_DISCONNECT);
2249 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2250 SCPY(e_tone, cause);
2252 set_tone(portlist, cause);
2253 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2254 portlist = portlist->next;
2256 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2259 /* port MESSAGE_NOTIFY */
2260 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2262 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2264 struct lcr_msg *message;
2266 /* signal to call tool */
2267 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);
2268 if (param->notifyinfo.notify) {
2269 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2272 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2273 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2274 case INFO_NOTIFY_REMOTE_HOLD:
2275 case INFO_NOTIFY_USER_SUSPENDED:
2276 /* tell call about it */
2277 if (ea_endpoint->ep_join_id) {
2278 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2279 message->param.audiopath = 0;
2280 message_put(message);
2284 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2285 case INFO_NOTIFY_USER_RESUMED:
2286 /* set volume of rx and tx */
2287 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2288 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2290 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2291 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2292 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2293 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2294 message_put(message);
2296 /* set current tone */
2298 set_tone(portlist, e_tone);
2299 /* tell call about it */
2300 if (ea_endpoint->ep_join_id) {
2301 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2302 message->param.audiopath = 1;
2303 message_put(message);
2308 /* notify call if available */
2309 if (ea_endpoint->ep_join_id) {
2310 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2311 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2312 message_put(message);
2317 /* port MESSAGE_PROGRESS */
2318 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2320 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2322 struct lcr_msg *message;
2324 /* signal to call tool */
2325 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2327 /* send progress to call if available */
2328 if (ea_endpoint->ep_join_id) {
2329 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2330 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2331 message_put(message);
2336 /* port MESSAGE_FACILITY */
2337 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2339 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2341 struct lcr_msg *message;
2343 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2344 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2345 message_put(message);
2348 /* port MESSAGE_3PTY */
2349 void EndpointAppPBX::port_3pty(struct port_list *portlist, int message_type, union parameter *param)
2351 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2353 struct lcr_msg *message;
2357 if (param->threepty.begin)
2358 rc = join_3pty_dss1();
2359 else if (param->threepty.end)
2364 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_3PTY);
2365 message->param.threepty.begin = param->threepty.begin;
2366 message->param.threepty.end = param->threepty.end;
2368 message->param.threepty.error = 1;
2370 message->param.threepty.result = 1;
2371 message->param.threepty.invoke_id = param->threepty.invoke_id;
2372 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2373 message_put(message);
2376 /* port MESSAGE_TRANSFER */
2377 void EndpointAppPBX::port_transfer(struct port_list *portlist, int message_type, union parameter *param)
2379 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2383 /* bridge for real */
2384 if (!(port = find_port_id(portlist->port_id)))
2386 if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS)
2388 else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1)
2392 /* port MESSAGE_SUSPEND */
2393 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2394 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2396 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2398 /* epoint is now parked */
2399 ea_endpoint->ep_park = 1;
2400 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2401 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2403 /* remove port relation */
2404 ea_endpoint->free_portlist(portlist);
2407 /* port MESSAGE_RESUME */
2408 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2409 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2411 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2413 /* epoint is now resumed */
2414 ea_endpoint->ep_park = 0;
2418 /* port MESSAGE_ENABLEKEYPAD */
2419 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2421 struct lcr_msg *message;
2423 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2425 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2426 memcpy(&message->param, param, sizeof(union parameter));
2427 message_put(message);
2431 /* port MESSAGE_DISABLE_DEJITTER */
2432 void EndpointAppPBX::port_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
2434 struct lcr_msg *message;
2436 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2438 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DISABLE_DEJITTER);
2439 memcpy(&message->param, param, sizeof(union parameter));
2440 message_put(message);
2444 /* port MESSAGE_UPDATEBRIDGE */
2445 void EndpointAppPBX::port_updatebridge(struct port_list *portlist, int message_type, union parameter *param)
2447 struct lcr_msg *message;
2449 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_UPDATEBRIDGE);
2450 message_put(message);
2454 /* port MESSAGE_VOOTP */
2455 void EndpointAppPBX::port_vootp(struct port_list *portlist, int message_type, union parameter *param)
2457 if (param->vootp.failed)
2458 set_tone(ea_endpoint->ep_portlist, "crypt_off");
2462 /* port sends message to the endpoint
2464 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2466 struct port_list *portlist;
2468 portlist = ea_endpoint->ep_portlist;
2470 if (port_id == portlist->port_id)
2472 portlist = portlist->next;
2475 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);
2479 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2480 switch(message_type) {
2481 case MESSAGE_TONE_EOF: /* tone is end of file */
2482 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2484 if (e_action->index == ACTION_VBOX_PLAY) {
2487 if (e_action->index == ACTION_EFI) {
2493 case MESSAGE_TONE_COUNTER: /* counter info received */
2494 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);
2496 if (e_action->index == ACTION_VBOX_PLAY) {
2497 e_vbox_counter = param->counter.current;
2498 if (param->counter.max >= 0)
2499 e_vbox_counter_max = param->counter.max;
2503 /* PORT sends SETUP message */
2505 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);
2506 if (e_state!=EPOINT_STATE_IDLE) {
2507 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2510 port_setup(portlist, message_type, param);
2513 /* PORT sends INFORMATION message */
2514 case MESSAGE_INFORMATION: /* additional digits received */
2515 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);
2516 port_information(portlist, message_type, param);
2519 /* PORT sends FACILITY message */
2520 case MESSAGE_FACILITY:
2521 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2522 port_facility(portlist, message_type, param);
2526 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming 3PTY facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2527 port_3pty(portlist, message_type, param);
2530 case MESSAGE_TRANSFER:
2531 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming TRANSFER request (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2532 port_transfer(portlist, message_type, param);
2535 /* PORT sends DTMF message */
2536 case MESSAGE_DTMF: /* dtmf digits received */
2537 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);
2538 port_dtmf(portlist, message_type, param);
2541 /* PORT sends CRYPT message */
2542 case MESSAGE_CRYPT: /* crypt response received */
2543 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2544 port_crypt(portlist, message_type, param);
2547 /* PORT sends MORE message */
2548 case MESSAGE_OVERLAP:
2549 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);
2550 if (e_state != EPOINT_STATE_OUT_SETUP) {
2551 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);
2554 port_overlap(portlist, message_type, param);
2557 /* PORT sends PROCEEDING message */
2558 case MESSAGE_PROCEEDING: /* port is proceeding */
2559 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);
2560 if (e_state!=EPOINT_STATE_OUT_SETUP
2561 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2562 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);
2565 port_proceeding(portlist, message_type, param);
2568 /* PORT sends ALERTING message */
2569 case MESSAGE_ALERTING:
2570 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);
2571 if (e_state!=EPOINT_STATE_OUT_SETUP
2572 && e_state!=EPOINT_STATE_OUT_OVERLAP
2573 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2574 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);
2577 port_alerting(portlist, message_type, param);
2580 /* PORT sends CONNECT message */
2581 case MESSAGE_CONNECT:
2582 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);
2583 if (e_state!=EPOINT_STATE_OUT_SETUP
2584 && e_state!=EPOINT_STATE_OUT_OVERLAP
2585 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2586 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2587 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2590 port_connect(portlist, message_type, param);
2593 /* PORT sends DISCONNECT message */
2594 case MESSAGE_DISCONNECT: /* port is disconnected */
2595 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);
2596 port_disconnect_release(portlist, message_type, param);
2599 /* PORT sends a RELEASE message */
2600 case MESSAGE_RELEASE: /* port releases */
2601 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);
2602 /* portlist is release at port_disconnect_release, thanx Paul */
2603 port_disconnect_release(portlist, message_type, param);
2606 /* PORT sends a TIMEOUT message */
2607 case MESSAGE_TIMEOUT:
2608 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);
2609 port_timeout(portlist, message_type, param);
2610 break; /* release */
2612 /* PORT sends a NOTIFY message */
2613 case MESSAGE_NOTIFY:
2614 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);
2615 port_notify(portlist, message_type, param);
2618 /* PORT sends a PROGRESS message */
2619 case MESSAGE_PROGRESS:
2620 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);
2621 port_progress(portlist, message_type, param);
2624 /* PORT sends a SUSPEND message */
2625 case MESSAGE_SUSPEND:
2626 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);
2627 port_suspend(portlist, message_type, param);
2628 break; /* suspend */
2630 /* PORT sends a RESUME message */
2631 case MESSAGE_RESUME:
2632 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);
2633 port_resume(portlist, message_type, param);
2637 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2638 /* port assigns bchannel */
2639 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2640 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);
2641 /* only one port is expected to be connected to bchannel */
2642 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2643 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2647 /* PORT requests DTMF */
2648 case MESSAGE_ENABLEKEYPAD:
2649 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);
2650 port_enablekeypad(portlist, message_type, param);
2653 case MESSAGE_DISABLE_DEJITTER:
2654 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);
2655 port_disable_dejitter(portlist, message_type, param);
2658 case MESSAGE_UPDATEBRIDGE:
2659 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming updatebridge message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2660 port_updatebridge(portlist, message_type, param);
2664 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming vootp message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2665 port_vootp(portlist, message_type, param);
2670 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);
2673 /* Note: this endpoint may be destroyed, so we MUST return */
2677 /* messages from join
2679 /* join MESSAGE_CRYPT */
2680 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2683 switch(param->crypt.type) {
2684 /* message from remote port to "crypt manager" */
2685 case CU_ACTK_REQ: /* activate key-exchange */
2686 case CU_ACTS_REQ: /* activate shared key */
2687 case CU_DACT_REQ: /* deactivate */
2688 case CU_INFO_REQ: /* request last info message */
2689 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2692 /* message from "crypt manager" to user */
2693 case CU_ACTK_CONF: /* key-echange done */
2694 case CU_ACTS_CONF: /* shared key done */
2695 case CU_DACT_CONF: /* deactivated */
2696 case CU_DACT_IND: /* deactivated */
2697 case CU_ERROR_IND: /* receive error message */
2698 case CU_INFO_IND: /* receive info message */
2699 case CU_INFO_CONF: /* receive info message */
2700 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2704 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);
2709 /* join MESSAGE_INFORMATION */
2710 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2712 struct lcr_msg *message;
2717 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2718 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2719 message_put(message);
2720 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2721 portlist = portlist->next;
2725 /* join MESSAGE_FACILITY */
2726 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2728 struct lcr_msg *message;
2730 if (!e_ext.facility && e_ext.number[0]) {
2735 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2736 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2737 message_put(message);
2738 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2739 portlist = portlist->next;
2743 /* join MESSAGE_MORE */
2744 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2746 struct lcr_msg *message;
2748 new_state(EPOINT_STATE_IN_OVERLAP);
2751 if (e_join_pattern && e_ext.own_setup) {
2752 /* disconnect audio */
2753 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2754 message->param.audiopath = 0;
2755 message_put(message);
2757 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2758 if (e_dialinginfo.id[0])
2759 set_tone(portlist, "dialing");
2761 set_tone(portlist, "dialtone");
2764 if (e_dialinginfo.id[0]) {
2765 set_tone(portlist, "dialing");
2767 if (e_ext.number[0])
2768 set_tone(portlist, "dialpbx");
2770 set_tone(portlist, "dialtone");
2774 /* join MESSAGE_PROCEEDING */
2775 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2777 struct lcr_msg *message;
2779 new_state(EPOINT_STATE_IN_PROCEEDING);
2781 /* own proceeding tone */
2782 if (e_join_pattern) {
2783 /* connect / disconnect audio */
2784 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2785 if (e_ext.own_proceeding)
2786 message->param.audiopath = 0;
2788 message->param.audiopath = 1;
2789 message_put(message);
2791 // UCPY(e_join_tone, "proceeding");
2793 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2794 message_put(message);
2795 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2797 set_tone(portlist, "proceeding");
2800 /* join MESSAGE_ALERTING */
2801 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2803 struct lcr_msg *message;
2805 new_state(EPOINT_STATE_IN_ALERTING);
2807 /* own alerting tone */
2808 if (e_join_pattern) {
2809 /* connect / disconnect audio */
2810 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2811 if (e_ext.own_alerting)
2812 message->param.audiopath = 0;
2814 message->param.audiopath = 1;
2815 message_put(message);
2818 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2819 message_put(message);
2820 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2822 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2823 set_tone(portlist, "ringing");
2826 if (e_ext.number[0])
2827 set_tone(portlist, "ringpbx");
2829 set_tone(portlist, "ringing");
2831 if (e_ext.number[0])
2832 e_dtmf = 1; /* allow dtmf */
2835 /* join MESSAGE_CONNECT */
2836 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2838 struct lcr_msg *message;
2841 new_state(EPOINT_STATE_CONNECT);
2842 // UCPY(e_join_tone, "");
2844 if (e_ext.number[0])
2845 e_dtmf = 1; /* allow dtmf */
2848 unsched_timer(&e_powerdial_timeout);
2849 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2851 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2852 memcpy(&message->param, param, sizeof(union parameter));
2854 /* screen clip if prefix is required */
2855 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2856 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2857 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2858 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2861 /* use internal caller id */
2862 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2863 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2864 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2867 /* handle restricted caller ids */
2868 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);
2869 /* display callerid if desired for extension */
2870 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));
2872 /* use conp, if enabld */
2873 // if (!e_ext.centrex)
2874 // message->param.connectinfo.name[0] = '\0';
2877 message_put(message);
2878 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2880 set_tone(portlist, NULL);
2882 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2883 message->param.audiopath = 1;
2884 message_put(message);
2889 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2890 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2893 struct lcr_msg *message;
2894 struct port_list *portlist = NULL;
2898 /* be sure that we are active */
2900 e_tx_state = NOTIFY_STATE_ACTIVE;
2902 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2903 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2904 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2906 /* set time for power dialing */
2907 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2910 /* set redial tone */
2911 if (ea_endpoint->ep_portlist) {
2914 set_tone(ea_endpoint->ep_portlist, "redial");
2915 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);
2916 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2917 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2918 new_state(EPOINT_STATE_IN_PROCEEDING);
2919 if (ea_endpoint->ep_portlist) {
2920 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2921 message_put(message);
2922 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2924 /* caused the error, that the first knock sound was not there */
2925 /* set_tone(portlist, "proceeding"); */
2927 /* send display of powerdialing */
2928 if (e_ext.display_dialing) {
2929 portlist = ea_endpoint->ep_portlist;
2931 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2933 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2935 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2936 message_put(message);
2937 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2938 portlist = portlist->next;
2948 if ((e_state!=EPOINT_STATE_CONNECT
2949 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2950 && e_state!=EPOINT_STATE_IN_OVERLAP
2951 && e_state!=EPOINT_STATE_IN_PROCEEDING
2952 && e_state!=EPOINT_STATE_IN_ALERTING)
2953 || !ea_endpoint->ep_portlist) { /* or no port */
2954 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2955 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2956 return; /* must exit here */
2959 if (!e_join_cause) {
2960 e_join_cause = param->disconnectinfo.cause;
2961 e_join_location = param->disconnectinfo.location;
2964 /* on release we need the audio again! */
2965 if (message_type == MESSAGE_RELEASE) {
2967 ea_endpoint->ep_join_id = 0;
2969 /* disconnect and select tone */
2970 new_state(EPOINT_STATE_OUT_DISCONNECT);
2971 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2972 /* if own_cause, we must release the join */
2973 if (e_ext.own_cause /* own cause */
2974 || !e_join_pattern) { /* no patterns */
2975 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);
2976 if (message_type != MESSAGE_RELEASE)
2977 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2979 } else { /* else we enable audio */
2980 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2981 message->param.audiopath = 1;
2982 message_put(message);
2984 /* send disconnect message */
2985 SCPY(e_tone, cause);
2986 portlist = ea_endpoint->ep_portlist;
2988 set_tone(portlist, cause);
2989 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2990 portlist = portlist->next;
2994 /* join MESSAGE_SETUP */
2995 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2997 struct lcr_msg *message;
2998 // struct interface *interface;
3000 /* if we already in setup state, we just update the dialing with new digits */
3001 if (e_state == EPOINT_STATE_OUT_SETUP
3002 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3003 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3004 /* if digits changed, what we have already dialed */
3005 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3006 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);
3007 /* release all ports */
3008 while((portlist = ea_endpoint->ep_portlist)) {
3009 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3010 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3011 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3012 message_put(message);
3013 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3014 ea_endpoint->free_portlist(portlist);
3017 /* disconnect audio */
3018 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3019 message->param.audiopath = 0;
3020 message_put(message);
3022 /* get dialing info */
3023 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3024 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3025 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3026 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3027 new_state(EPOINT_STATE_OUT_OVERLAP);
3030 schedule_timer(&e_redial_timeout, 1, 0);
3033 /* if we have a pending redial, so we just adjust the dialing number */
3034 if (e_redial_timeout.active) {
3035 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);
3036 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3039 if (!ea_endpoint->ep_portlist) {
3040 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3042 if (ea_endpoint->ep_portlist->next) {
3043 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3045 if (e_state == EPOINT_STATE_OUT_SETUP) {
3047 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);
3048 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3051 /* get what we have not dialed yet */
3052 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));
3053 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3054 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3055 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3056 message_put(message);
3057 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3059 /* always store what we have dialed or queued */
3060 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3064 if (e_state != EPOINT_STATE_IDLE) {
3065 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3068 /* if an internal extension is dialed, copy that number */
3069 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3070 SCPY(e_ext.number, param->setup.dialinginfo.id);
3071 /* if an internal extension is dialed, get extension's info about caller */
3072 if (e_ext.number[0]) {
3073 if (!read_extension(&e_ext, e_ext.number)) {
3074 e_ext.number[0] = '\0';
3075 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3079 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3080 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3081 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3082 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3083 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3085 /* process (voice over) data calls */
3086 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3087 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3088 memset(&e_capainfo, 0, sizeof(e_capainfo));
3089 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3090 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3091 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3094 new_state(EPOINT_STATE_OUT_SETUP);
3095 /* call special setup routine */
3099 /* join MESSAGE_mISDNSIGNAL */
3100 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3102 struct lcr_msg *message;
3105 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3106 memcpy(&message->param, param, sizeof(union parameter));
3107 message_put(message);
3108 portlist = portlist->next;
3112 /* join MESSAGE_BRIDE */
3113 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3115 struct lcr_msg *message;
3118 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3119 memcpy(&message->param, param, sizeof(union parameter));
3120 message_put(message);
3121 portlist = portlist->next;
3125 /* join MESSAGE_NOTIFY */
3126 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3128 struct lcr_msg *message;
3131 if (param->notifyinfo.notify) {
3132 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3133 // /* if notification was generated locally, we turn hold music on/off */
3134 // if (param->notifyinfo.local)
3135 // 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)
3139 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3140 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3142 set_tone(portlist, "");
3143 portlist = portlist->next;
3146 portlist = ea_endpoint->ep_portlist;
3151 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3153 set_tone(portlist, "hold");
3154 portlist = portlist->next;
3156 portlist = ea_endpoint->ep_portlist;
3161 /* save new state */
3162 e_tx_state = new_state;
3165 /* notify port(s) about it */
3167 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3168 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3169 /* handle restricted caller ids */
3170 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3171 /* display callerid if desired for extension */
3172 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));
3173 message_put(message);
3174 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3175 portlist = portlist->next;
3179 /* join MESSAGE_DTMF */
3180 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3182 struct lcr_msg *message;
3185 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3186 memcpy(&message->param, param, sizeof(union parameter));
3187 message_put(message);
3188 portlist = portlist->next;
3192 /* join MESSAGE_DISABLE_DEJITTER */
3193 void EndpointAppPBX::join_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
3195 struct lcr_msg *message;
3198 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISABLE_DEJITTER);
3199 memcpy(&message->param, param, sizeof(union parameter));
3200 message_put(message);
3201 portlist = portlist->next;
3205 /* JOIN sends messages to the endpoint
3207 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3209 struct port_list *portlist;
3210 struct lcr_msg *message;
3213 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3217 portlist = ea_endpoint->ep_portlist;
3219 // 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);
3220 switch(message_type) {
3221 /* JOIN SENDS TONE message */
3223 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);
3224 set_tone(portlist, param->tone.name);
3227 /* JOIN SENDS CRYPT message */
3229 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);
3230 join_crypt(portlist, message_type, param);
3233 /* JOIN sends INFORMATION message */
3234 case MESSAGE_INFORMATION:
3235 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);
3236 join_information(portlist, message_type, param);
3239 /* JOIN sends FACILITY message */
3240 case MESSAGE_FACILITY:
3241 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);
3242 join_facility(portlist, message_type, param);
3245 /* JOIN sends OVERLAP message */
3246 case MESSAGE_OVERLAP:
3247 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);
3248 if (e_state!=EPOINT_STATE_IN_SETUP
3249 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3250 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3253 join_overlap(portlist, message_type, param);
3256 /* JOIN sends PROCEEDING message */
3257 case MESSAGE_PROCEEDING:
3258 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);
3259 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3260 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3263 join_proceeding(portlist, message_type, param);
3266 /* JOIN sends ALERTING message */
3267 case MESSAGE_ALERTING:
3268 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);
3269 if (e_state!=EPOINT_STATE_IN_OVERLAP
3270 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3271 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3274 join_alerting(portlist, message_type, param);
3277 /* JOIN sends CONNECT message */
3278 case MESSAGE_CONNECT:
3279 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);
3280 if (e_state!=EPOINT_STATE_IN_OVERLAP
3281 && e_state!=EPOINT_STATE_IN_PROCEEDING
3282 && e_state!=EPOINT_STATE_IN_ALERTING) {
3283 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3286 join_connect(portlist, message_type, param);
3289 /* JOIN sends DISCONNECT/RELEASE message */
3290 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3291 case MESSAGE_RELEASE: /* JOIN releases */
3292 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);
3293 join_disconnect_release(message_type, param);
3296 /* JOIN sends SETUP message */
3298 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);
3299 join_setup(portlist, message_type, param);
3302 /* JOIN sends special mISDNSIGNAL message */
3303 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3304 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);
3305 join_mISDNsignal(portlist, message_type, param);
3308 /* JOIN sends bridge message */
3309 case MESSAGE_BRIDGE: /* bride message to port */
3310 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);
3311 join_bridge(portlist, message_type, param);
3314 /* JOIN has pattern available */
3315 case MESSAGE_PATTERN: /* indicating pattern available */
3316 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);
3317 if (!e_join_pattern) {
3318 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3322 set_tone(portlist, NULL);
3323 portlist = portlist->next;
3325 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3326 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3327 message->param.audiopath = 1;
3328 message_put(message);
3332 /* JOIN has no pattern available */
3333 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3334 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);
3335 if (e_join_pattern) {
3336 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3338 /* disconnect our audio tx and rx */
3339 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3340 message->param.audiopath = 0;
3341 message_put(message);
3346 /* JOIN (dunno at the moment) */
3347 case MESSAGE_REMOTE_AUDIO:
3348 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);
3349 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3350 message->param.audiopath = param->channel;
3351 message_put(message);
3355 /* JOIN sends a notify message */
3356 case MESSAGE_NOTIFY:
3357 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);
3358 join_notify(portlist, message_type, param);
3361 /* JOIN wants keypad / dtmf */
3362 case MESSAGE_ENABLEKEYPAD:
3363 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);
3366 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3370 /* JOIN sends a DTMF message */
3372 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);
3373 join_dtmf(portlist, message_type, param);
3376 /* JOIN sends a DISABLE_DEJITTER message */
3377 case MESSAGE_DISABLE_DEJITTER:
3378 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);
3379 join_disable_dejitter(portlist, message_type, param);
3383 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);
3388 /* pick_join will connect the first incoming call found. the endpoint
3389 * will receivce a MESSAGE_CONNECT.
3391 int match_list(char *list, char *item)
3393 char *end, *next = NULL;
3395 /* no list make matching */
3400 /* eliminate white spaces */
3401 while (*list > '\0' && *list <= ' ')
3407 /* if end of list is reached, we return */
3408 if (list[0] == '\0')
3410 /* if we have more than one entry (left) */
3411 if ((end = strchr(list, ',')))
3414 next = end = strchr(list, '\0');
3415 while (*(end-1) <= ' ')
3417 /* if string part matches item */
3418 if (!strncmp(list, item, end-list))
3424 void EndpointAppPBX::pick_join(char *extensions)
3426 struct lcr_msg *message;
3427 struct port_list *portlist;
3429 class EndpointAppPBX *eapp, *found;
3431 class JoinPBX *joinpbx;
3432 struct join_relation *relation;
3434 /* find an endpoint that is ringing internally or vbox with higher priority */
3436 eapp = apppbx_first;
3438 if (eapp!=this && ea_endpoint->ep_portlist) {
3439 portlist = eapp->ea_endpoint->ep_portlist;
3441 if ((port = find_port_id(portlist->port_id))) {
3442 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3443 if (match_list(extensions, eapp->e_ext.number)) {
3448 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3449 && port->p_state==PORT_STATE_OUT_ALERTING)
3450 if (match_list(extensions, eapp->e_ext.number)) {
3454 portlist = portlist->next;
3462 /* if no endpoint found */
3464 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);
3466 set_tone(ea_endpoint->ep_portlist, "cause_10");
3467 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3468 new_state(EPOINT_STATE_OUT_DISCONNECT);
3473 if (ea_endpoint->ep_join_id) {
3474 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3477 if (!eapp->ea_endpoint->ep_join_id) {
3478 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3481 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3483 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3486 if (join->j_type != JOIN_TYPE_PBX) {
3487 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3490 joinpbx = (class JoinPBX *)join;
3491 relation = joinpbx->j_relation;
3493 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3496 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3497 relation = relation->next;
3499 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3504 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3506 if (options.deb & DEBUG_EPOINT) {
3507 class Join *debug_c = join_first;
3508 class Endpoint *debug_e = epoint_first;
3509 class Port *debug_p = port_first;
3511 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3513 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3515 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3516 debug_c = debug_c->next;
3518 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3520 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3521 debug_e = debug_e->next;
3523 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3525 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3526 debug_p = debug_p->next;
3531 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3532 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3533 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3535 /* connnecting our endpoint */
3536 new_state(EPOINT_STATE_CONNECT);
3537 if (e_ext.number[0])
3539 set_tone(ea_endpoint->ep_portlist, NULL);
3541 /* now we send a release to the ringing endpoint */
3542 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3543 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3544 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3545 message_put(message);
3547 /* we send a connect to the join with our caller id */
3548 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3549 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3550 message->param.connectinfo.present = e_callerinfo.present;
3551 message->param.connectinfo.screen = e_callerinfo.screen;
3552 message->param.connectinfo.itype = e_callerinfo.itype;
3553 message->param.connectinfo.ntype = e_callerinfo.ntype;
3554 message_put(message);
3556 /* we send a connect to our port with the remote callerid */
3557 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3558 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3559 message->param.connectinfo.present = eapp->e_callerinfo.present;
3560 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3561 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3562 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3563 /* handle restricted caller ids */
3564 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);
3565 /* display callerid if desired for extension */
3566 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));
3567 message_put(message);
3569 /* we send a connect to the audio path (not for vbox) */
3570 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3571 message->param.audiopath = 1;
3572 message_put(message);
3574 /* beeing paranoid, we make call update */
3575 trigger_work(&joinpbx->j_updatebridge);
3577 if (options.deb & DEBUG_EPOINT) {
3578 class Join *debug_c = join_first;
3579 class Endpoint *debug_e = epoint_first;
3580 class Port *debug_p = port_first;
3582 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3584 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3586 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3587 debug_c = debug_c->next;
3589 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3591 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3592 debug_e = debug_e->next;
3594 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3596 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3597 debug_p = debug_p->next;
3603 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3605 int EndpointAppPBX::join_join_dss1(void)
3608 struct lcr_msg *message;
3609 struct join_relation *add_relation, *remove_relation;
3610 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3611 class Join *our_join, *other_join, *add_join, *remove_join;
3612 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3613 class EndpointAppPBX *other_eapp, *remove_eapp;
3614 class Port *our_port, *other_port;
3615 class Pdss1 *our_pdss1, *other_pdss1;
3616 class Endpoint *temp_epoint;
3618 /* are we a candidate to join a join? */
3619 our_join = find_join_id(ea_endpoint->ep_join_id);
3621 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3624 if (our_join->j_type != JOIN_TYPE_PBX) {
3625 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3628 our_joinpbx = (class JoinPBX *)our_join;
3629 if (!ea_endpoint->ep_portlist) {
3630 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3633 if (!e_ext.number[0]) {
3634 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3637 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3639 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3642 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3643 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3646 our_pdss1 = (class Pdss1 *)our_port;
3648 /* find an endpoint that has the same mISDNport/ces that we are on */
3649 other_eapp = apppbx_first;
3651 if (other_eapp == this) {
3652 other_eapp = other_eapp->next;
3655 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);
3656 if (other_eapp->e_ext.number[0] /* has terminal */
3657 && other_eapp->ea_endpoint->ep_portlist /* has port */
3658 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3659 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3660 if (other_port) { /* port still exists */
3661 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3662 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3663 other_pdss1 = (class Pdss1 *)other_port;
3664 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);
3665 if (1 //other_pdss1->p_m_hold /* port is on hold */
3666 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3667 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3670 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3673 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3676 other_eapp = other_eapp->next;
3679 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3682 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3684 /* if we have the same join */
3685 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3686 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3689 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3691 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3694 if (other_join->j_type != JOIN_TYPE_PBX) {
3695 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3698 other_joinpbx = (class JoinPBX *)other_join;
3699 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3700 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3704 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3705 if (our_pdss1->p_m_hold && !other_pdss1->p_m_hold) {
3706 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);
3708 remove_join = our_join;
3709 remove_joinpbx = our_joinpbx;
3710 add_join = other_join;
3711 add_joinpbx = other_joinpbx;
3713 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);
3714 remove_eapp = other_eapp;
3715 remove_join = other_join;
3716 remove_joinpbx = other_joinpbx;
3717 add_join = our_join;
3718 add_joinpbx = our_joinpbx;
3721 /* remove relation to endpoint for join on hold */
3722 remove_relation = remove_joinpbx->j_relation;
3723 remove_relation_pointer = &remove_joinpbx->j_relation;
3724 while(remove_relation) {
3725 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3726 /* detach other endpoint */
3727 *remove_relation_pointer = remove_relation->next;
3728 FREE(remove_relation, sizeof(struct join_relation));
3730 remove_relation = *remove_relation_pointer;
3731 remove_eapp->ea_endpoint->ep_join_id = 0;
3735 /* change join/hold pointer of endpoint to the new join */
3736 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3738 if (temp_epoint->ep_join_id == remove_join->j_serial)
3739 temp_epoint->ep_join_id = add_join->j_serial;
3742 remove_relation_pointer = &remove_relation->next;
3743 remove_relation = remove_relation->next;
3745 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3747 /* join call relations */
3748 add_relation = add_joinpbx->j_relation;
3749 add_relation_pointer = &add_joinpbx->j_relation;
3750 while(add_relation) {
3751 add_relation_pointer = &add_relation->next;
3752 add_relation = add_relation->next;
3754 *add_relation_pointer = remove_joinpbx->j_relation;
3755 remove_joinpbx->j_relation = NULL;
3756 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3758 /* release endpoint */
3759 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3760 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3761 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3762 message_put(message);
3764 /* if we are not a partyline, we get partyline state from other join */
3765 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3767 /* remove empty join */
3769 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3771 /* mixer must update */
3772 trigger_work(&add_joinpbx->j_updatebridge);
3774 /* we send a retrieve to that endpoint */
3775 // mixer will update the hold-state of the join and send it to the endpoints is changes
3777 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3783 /* join calls (look for a join that is on hold (same fxs interface/terminal))
3785 int EndpointAppPBX::join_join_fxs(void)
3788 struct lcr_msg *message;
3789 struct join_relation *add_relation, *remove_relation;
3790 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3791 class Join *our_join, *other_join, *add_join, *remove_join;
3792 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3793 class EndpointAppPBX *other_eapp, *remove_eapp;
3794 class Port *our_port, *other_port;
3795 class Pfxs *our_fxs, *other_fxs;
3796 class Endpoint *temp_epoint;
3798 /* are we a candidate to join a join? */
3799 our_join = find_join_id(ea_endpoint->ep_join_id);
3801 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3804 if (our_join->j_type != JOIN_TYPE_PBX) {
3805 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3808 our_joinpbx = (class JoinPBX *)our_join;
3809 if (!ea_endpoint->ep_portlist) {
3810 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3813 if (!e_ext.number[0]) {
3814 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3817 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3819 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3822 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
3823 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not fxs.\n", ea_endpoint->ep_serial);
3826 our_fxs = (class Pfxs *)our_port;
3828 /* find an endpoint that has the same mISDNport that we are on */
3829 other_eapp = apppbx_first;
3831 if (other_eapp == this) {
3832 other_eapp = other_eapp->next;
3835 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);
3836 if (other_eapp->e_ext.number[0] /* has terminal */
3837 && other_eapp->ea_endpoint->ep_portlist /* has port */
3838 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3839 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3840 if (other_port) { /* port still exists */
3841 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
3842 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is FXS */
3843 other_fxs = (class Pfxs *)other_port;
3844 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);
3845 if (1 //other_fxs->p_m_hold /* port is on hold */
3846 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
3849 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3852 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3855 other_eapp = other_eapp->next;
3858 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
3861 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3863 /* if we have the same join */
3864 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3865 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3868 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3870 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3873 if (other_join->j_type != JOIN_TYPE_PBX) {
3874 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3877 other_joinpbx = (class JoinPBX *)other_join;
3878 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3879 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3883 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3884 if (our_fxs->p_m_hold && !other_fxs->p_m_hold) {
3885 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);
3887 remove_join = our_join;
3888 remove_joinpbx = our_joinpbx;
3889 add_join = other_join;
3890 add_joinpbx = other_joinpbx;
3892 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);
3893 remove_eapp = other_eapp;
3894 remove_join = other_join;
3895 remove_joinpbx = other_joinpbx;
3896 add_join = our_join;
3897 add_joinpbx = our_joinpbx;
3900 /* remove relation to endpoint for join on hold */
3901 remove_relation = remove_joinpbx->j_relation;
3902 remove_relation_pointer = &remove_joinpbx->j_relation;
3903 while(remove_relation) {
3904 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3905 /* detach other endpoint */
3906 *remove_relation_pointer = remove_relation->next;
3907 FREE(remove_relation, sizeof(struct join_relation));
3909 remove_relation = *remove_relation_pointer;
3910 remove_eapp->ea_endpoint->ep_join_id = 0;
3914 /* change join/hold pointer of endpoint to the new join */
3915 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3917 if (temp_epoint->ep_join_id == remove_join->j_serial)
3918 temp_epoint->ep_join_id = add_join->j_serial;
3921 remove_relation_pointer = &remove_relation->next;
3922 remove_relation = remove_relation->next;
3924 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3926 /* join call relations */
3927 add_relation = add_joinpbx->j_relation;
3928 add_relation_pointer = &add_joinpbx->j_relation;
3929 while(add_relation) {
3930 add_relation_pointer = &add_relation->next;
3931 add_relation = add_relation->next;
3933 *add_relation_pointer = remove_joinpbx->j_relation;
3934 remove_joinpbx->j_relation = NULL;
3935 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3937 /* release endpoint */
3938 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3939 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3940 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3941 message_put(message);
3943 /* if we are not a partyline, we get partyline state from other join */
3944 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3946 /* remove empty join */
3948 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3950 /* mixer must update */
3951 trigger_work(&add_joinpbx->j_updatebridge);
3953 /* we send a retrieve to that endpoint */
3954 // mixer will update the hold-state of the join and send it to the endpoints is changes
3956 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3962 int EndpointAppPBX::join_3pty_dss1(void)
3965 class Join *our_join, *other_join;
3966 class JoinPBX *our_joinpbx, *other_joinpbx;
3967 class EndpointAppPBX *other_eapp;
3968 class Port *our_port, *other_port;
3969 class Pdss1 *our_pdss1, *other_pdss1;
3971 /* are we a candidate to join a join? */
3972 our_join = find_join_id(ea_endpoint->ep_join_id);
3974 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3977 if (our_join->j_type != JOIN_TYPE_PBX) {
3978 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3981 our_joinpbx = (class JoinPBX *)our_join;
3982 if (!ea_endpoint->ep_portlist) {
3983 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3986 if (!e_ext.number[0]) {
3987 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3990 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3992 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3995 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3996 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3999 our_pdss1 = (class Pdss1 *)our_port;
4001 /* find an endpoint that has the same mISDNport/ces that we are on */
4002 other_eapp = apppbx_first;
4004 if (other_eapp == this) {
4005 other_eapp = other_eapp->next;
4008 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);
4009 if (other_eapp->e_ext.number[0] /* has terminal */
4010 && other_eapp->ea_endpoint->ep_portlist /* has port */
4011 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4012 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4013 if (other_port) { /* port still exists */
4014 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
4015 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
4016 other_pdss1 = (class Pdss1 *)other_port;
4017 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);
4018 if (1 //other_pdss1->p_m_hold /* port is on hold */
4019 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
4020 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
4023 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4026 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4029 other_eapp = other_eapp->next;
4032 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
4035 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4037 /* if we have the same join */
4038 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4039 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4042 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4044 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4047 if (other_join->j_type != JOIN_TYPE_PBX) {
4048 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4051 other_joinpbx = (class JoinPBX *)other_join;
4052 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4053 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4057 if (our_joinpbx->j_3pty) {
4058 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4061 if (other_joinpbx->j_3pty) {
4062 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4066 /* set 3PTY bridge */
4067 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4068 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4070 /* mixer must update */
4071 trigger_work(&our_joinpbx->j_updatebridge);
4072 trigger_work(&other_joinpbx->j_updatebridge);
4074 /* we send a retrieve to that endpoint */
4075 // mixer will update the hold-state of the join and send it to the endpoints is changes
4077 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4083 int EndpointAppPBX::join_3pty_fxs(void)
4086 class Join *our_join, *other_join;
4087 class JoinPBX *our_joinpbx, *other_joinpbx;
4088 class EndpointAppPBX *other_eapp;
4089 class Port *our_port, *other_port;
4090 class Pfxs *our_fxs, *other_fxs;
4092 /* are we a candidate to join a join? */
4093 our_join = find_join_id(ea_endpoint->ep_join_id);
4095 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4098 if (our_join->j_type != JOIN_TYPE_PBX) {
4099 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4102 our_joinpbx = (class JoinPBX *)our_join;
4103 if (!ea_endpoint->ep_portlist) {
4104 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4107 if (!e_ext.number[0]) {
4108 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4111 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4113 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4116 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
4117 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not FXS pots.\n", ea_endpoint->ep_serial);
4120 our_fxs = (class Pfxs *)our_port;
4122 /* find an endpoint that has the same mISDNport that we are on */
4123 other_eapp = apppbx_first;
4125 if (other_eapp == this) {
4126 other_eapp = other_eapp->next;
4129 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);
4130 if (other_eapp->e_ext.number[0] /* has terminal */
4131 && other_eapp->ea_endpoint->ep_portlist /* has port */
4132 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4133 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4134 if (other_port) { /* port still exists */
4135 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4136 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is isdn nt-mode */
4137 other_fxs = (class Pfxs *)other_port;
4138 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);
4139 if (1 //other_fxs->p_m_hold /* port is on hold */
4140 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
4143 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4146 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4149 other_eapp = other_eapp->next;
4152 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4155 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4157 /* if we have the same join */
4158 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4159 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4162 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4164 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4167 if (other_join->j_type != JOIN_TYPE_PBX) {
4168 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4171 other_joinpbx = (class JoinPBX *)other_join;
4172 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4173 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4177 if (our_joinpbx->j_3pty) {
4178 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4181 if (other_joinpbx->j_3pty) {
4182 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4186 /* set 3PTY bridge */
4187 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4188 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4190 /* mixer must update */
4191 trigger_work(&our_joinpbx->j_updatebridge);
4192 trigger_work(&other_joinpbx->j_updatebridge);
4194 /* we send a retrieve to that endpoint */
4195 // mixer will update the hold-state of the join and send it to the endpoints is changes
4197 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4203 int EndpointAppPBX::split_3pty(void)
4206 class Join *our_join, *other_join;
4207 class JoinPBX *our_joinpbx, *other_joinpbx;
4209 /* are we a candidate to join a join? */
4210 our_join = find_join_id(ea_endpoint->ep_join_id);
4212 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4215 if (our_join->j_type != JOIN_TYPE_PBX) {
4216 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4219 our_joinpbx = (class JoinPBX *)our_join;
4221 if (!our_joinpbx->j_3pty) {
4222 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
4226 other_join = find_join_id(our_joinpbx->j_3pty);
4228 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4231 if (other_join->j_type != JOIN_TYPE_PBX) {
4232 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4235 other_joinpbx = (class JoinPBX *)other_join;
4237 our_joinpbx->j_3pty = 0;
4238 other_joinpbx->j_3pty = 0;
4240 /* mixer must update */
4241 trigger_work(&our_joinpbx->j_updatebridge);
4242 trigger_work(&other_joinpbx->j_updatebridge);
4244 /* we send a retrieve to that endpoint */
4245 // mixer will update the hold-state of the join and send it to the endpoints is changes
4247 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4253 /* check if we have an external call
4254 * this is used to check for encryption ability
4256 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
4258 struct join_relation *relation;
4260 class JoinPBX *joinpbx;
4261 class Endpoint *epoint;
4263 /* some paranoia check */
4264 if (!ea_endpoint->ep_portlist) {
4265 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4266 *errstr = "No Call";
4269 if (!e_ext.number[0]) {
4270 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4271 *errstr = "No Call";
4275 /* check if we have a join with 2 parties */
4276 join = find_join_id(ea_endpoint->ep_join_id);
4278 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
4279 *errstr = "No Call";
4282 if (join->j_type != JOIN_TYPE_PBX) {
4283 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4284 *errstr = "No PBX Call";
4287 joinpbx = (class JoinPBX *)join;
4288 relation = joinpbx->j_relation;
4290 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4291 *errstr = "No Call";
4294 if (!relation->next) {
4295 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4296 *errstr = "No Call";
4299 if (relation->next->next) {
4300 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4301 *errstr = "Err: Conference";
4304 if (relation->epoint_id == ea_endpoint->ep_serial) {
4305 relation = relation->next;
4306 if (relation->epoint_id == ea_endpoint->ep_serial) {
4307 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4308 *errstr = "Software Error";
4313 /* check remote port for external call */
4314 epoint = find_epoint_id(relation->epoint_id);
4316 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4317 *errstr = "No Call";
4320 if (!epoint->ep_portlist) {
4321 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4322 *errstr = "No Call";
4325 *port = find_port_id(epoint->ep_portlist->port_id);
4327 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4328 *errstr = "No Call";
4331 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4332 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4333 *errstr = "No Ext Call";
4336 if ((*port)->p_state != PORT_STATE_CONNECT) {
4337 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4338 *errstr = "No Ext Connect";
4344 int EndpointAppPBX::vootp_on(int on)
4347 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4349 if (!e_ext.otp_ident[0]) {
4350 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4353 if(ea_endpoint->ep_portlist) {
4354 struct lcr_msg *message;
4356 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VOOTP);
4357 message->param.vootp.enable = on;
4358 SCPY(message->param.vootp.id, e_ext.otp_ident);
4359 message_put(message);
4362 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4368 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4370 const char *logtext = "unknown";
4373 switch(message_type) {
4375 trace_header("SETUP", 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);
4380 if (param->setup.callerinfo.extension[0])
4381 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4382 if (param->setup.callerinfo.interface[0])
4383 add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
4384 if (param->setup.dialinginfo.interfaces[0])
4385 add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
4386 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4387 switch(param->setup.callerinfo.present) {
4388 case INFO_PRESENT_RESTRICTED:
4389 add_trace("caller id", "present", "restricted");
4391 case INFO_PRESENT_ALLOWED:
4392 add_trace("caller id", "present", "allowed");
4395 add_trace("caller id", "present", "not available");
4397 if (param->setup.callerinfo.ntype2) {
4398 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4399 switch(param->setup.callerinfo.present) {
4400 case INFO_PRESENT_RESTRICTED:
4401 add_trace("caller id2", "present", "restricted");
4403 case INFO_PRESENT_ALLOWED:
4404 add_trace("caller id2", "present", "allowed");
4407 add_trace("caller id2", "present", "not available");
4410 if (param->setup.redirinfo.id[0]) {
4411 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4412 switch(param->setup.redirinfo.present) {
4413 case INFO_PRESENT_RESTRICTED:
4414 add_trace("redir'ing", "present", "restricted");
4416 case INFO_PRESENT_ALLOWED:
4417 add_trace("redir'ing", "present", "allowed");
4420 add_trace("redir'ing", "present", "not available");
4423 if (param->setup.dialinginfo.id[0])
4424 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4425 if (param->setup.dialinginfo.keypad[0])
4426 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4427 if (param->setup.dialinginfo.display[0])
4428 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4429 if (param->setup.dialinginfo.sending_complete)
4430 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4434 case MESSAGE_OVERLAP:
4435 trace_header("SETUP ACKNOWLEDGE", dir);
4436 if (dir == DIRECTION_OUT)
4437 add_trace("to", NULL, "CH(%lu)", port_id);
4438 if (dir == DIRECTION_IN)
4439 add_trace("from", NULL, "CH(%lu)", port_id);
4443 case MESSAGE_PROCEEDING:
4444 trace_header("PROCEEDING", dir);
4445 if (dir == DIRECTION_OUT)
4446 add_trace("to", NULL, "CH(%lu)", port_id);
4447 if (dir == DIRECTION_IN)
4448 add_trace("from", NULL, "CH(%lu)", port_id);
4452 case MESSAGE_ALERTING:
4453 trace_header("ALERTING", dir);
4454 if (dir == DIRECTION_OUT)
4455 add_trace("to", NULL, "CH(%lu)", port_id);
4456 if (dir == DIRECTION_IN)
4457 add_trace("from", NULL, "CH(%lu)", port_id);
4461 case MESSAGE_CONNECT:
4462 trace_header("CONNECT", dir);
4463 if (dir == DIRECTION_OUT)
4464 add_trace("to", NULL, "CH(%lu)", port_id);
4465 if (dir == DIRECTION_IN)
4466 add_trace("from", NULL, "CH(%lu)", port_id);
4467 if (param->connectinfo.extension[0])
4468 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4469 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4470 switch(param->connectinfo.present) {
4471 case INFO_PRESENT_RESTRICTED:
4472 add_trace("connect id", "present", "restricted");
4474 case INFO_PRESENT_ALLOWED:
4475 add_trace("connect id", "present", "allowed");
4478 add_trace("connect id", "present", "not available");
4480 if (param->connectinfo.display[0])
4481 add_trace("display", NULL, "%s", param->connectinfo.display);
4485 case MESSAGE_DISCONNECT:
4486 case MESSAGE_RELEASE:
4487 if (message_type == MESSAGE_DISCONNECT)
4488 trace_header("DISCONNECT", dir);
4490 trace_header("RELEASE", dir);
4491 if (dir == DIRECTION_OUT)
4492 add_trace("to", NULL, "CH(%lu)", port_id);
4493 if (dir == DIRECTION_IN)
4494 add_trace("from", NULL, "CH(%lu)", port_id);
4495 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4496 switch(param->disconnectinfo.location) {
4498 add_trace("cause", "location", "0-User");
4500 case LOCATION_PRIVATE_LOCAL:
4501 add_trace("cause", "location", "1-Local-PBX");
4503 case LOCATION_PUBLIC_LOCAL:
4504 add_trace("cause", "location", "2-Local-Exchange");
4506 case LOCATION_TRANSIT:
4507 add_trace("cause", "location", "3-Transit");
4509 case LOCATION_PUBLIC_REMOTE:
4510 add_trace("cause", "location", "4-Remote-Exchange");
4512 case LOCATION_PRIVATE_REMOTE:
4513 add_trace("cause", "location", "5-Remote-PBX");
4515 case LOCATION_INTERNATIONAL:
4516 add_trace("cause", "location", "7-International-Exchange");
4518 case LOCATION_BEYOND:
4519 add_trace("cause", "location", "10-Beyond-Interworking");
4522 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4524 if (param->disconnectinfo.display[0])
4525 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4529 case MESSAGE_NOTIFY:
4530 switch(param->notifyinfo.notify) {
4535 logtext = "USER_SUSPENDED";
4538 logtext = "BEARER_SERVICE_CHANGED";
4541 logtext = "USER_RESUMED";
4544 logtext = "CONFERENCE_ESTABLISHED";
4547 logtext = "CONFERENCE_DISCONNECTED";
4550 logtext = "OTHER_PARTY_ADDED";
4553 logtext = "ISOLATED";
4556 logtext = "REATTACHED";
4559 logtext = "OTHER_PARTY_ISOLATED";
4562 logtext = "OTHER_PARTY_REATTACHED";
4565 logtext = "OTHER_PARTY_SPLIT";
4568 logtext = "OTHER_PARTY_DISCONNECTED";
4571 logtext = "CONFERENCE_FLOATING";
4574 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4577 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4580 logtext = "CALL_IS_A_WAITING_CALL";
4583 logtext = "DIVERSION_ACTIVATED";
4586 logtext = "RESERVED_CT_1";
4589 logtext = "RESERVED_CT_2";
4592 logtext = "REVERSE_CHARGING";
4595 logtext = "REMOTE_HOLD";
4598 logtext = "REMOTE_RETRIEVAL";
4601 logtext = "CALL_IS_DIVERTING";
4604 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4608 trace_header("NOTIFY", dir);
4609 if (dir == DIRECTION_OUT)
4610 add_trace("to", NULL, "CH(%lu)", port_id);
4611 if (dir == DIRECTION_IN)
4612 add_trace("from", NULL, "CH(%lu)", port_id);
4613 if (param->notifyinfo.notify)
4614 add_trace("indicator", NULL, "%s", logtext);
4615 if (param->notifyinfo.id[0]) {
4616 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4617 switch(param->notifyinfo.present) {
4618 case INFO_PRESENT_RESTRICTED:
4619 add_trace("redir'on", "present", "restricted");
4621 case INFO_PRESENT_ALLOWED:
4622 add_trace("redir'on", "present", "allowed");
4625 add_trace("redir'on", "present", "not available");
4628 if (param->notifyinfo.display[0])
4629 add_trace("display", NULL, "%s", param->notifyinfo.display);
4633 case MESSAGE_PROGRESS:
4634 switch(param->progressinfo.progress) {
4636 logtext = "Call is not end to end ISDN";
4639 logtext = "Destination address is non-ISDN";
4642 logtext = "Origination address is non-ISDN";
4645 logtext = "Call has returned to the ISDN";
4648 logtext = "In-band info or pattern available";
4651 SPRINT(buffer, "%d", param->progressinfo.progress);
4655 trace_header("PROGRESS", dir);
4656 if (dir == DIRECTION_OUT)
4657 add_trace("to", NULL, "CH(%lu)", port_id);
4658 if (dir == DIRECTION_IN)
4659 add_trace("from", NULL, "CH(%lu)", port_id);
4660 add_trace("indicator", NULL, "%s", logtext);
4661 switch(param->progressinfo.location) {
4663 add_trace("cause", "location", "0-User");
4665 case LOCATION_PRIVATE_LOCAL:
4666 add_trace("cause", "location", "1-Local-PBX");
4668 case LOCATION_PUBLIC_LOCAL:
4669 add_trace("cause", "location", "2-Local-Exchange");
4671 case LOCATION_TRANSIT:
4672 add_trace("cause", "location", "3-Transit");
4674 case LOCATION_PUBLIC_REMOTE:
4675 add_trace("cause", "location", "4-Remote-Exchange");
4677 case LOCATION_PRIVATE_REMOTE:
4678 add_trace("cause", "location", "5-Remote-PBX");
4680 case LOCATION_INTERNATIONAL:
4681 add_trace("cause", "location", "7-International-Exchange");
4683 case LOCATION_BEYOND:
4684 add_trace("cause", "location", "10-Beyond-Interworking");
4687 add_trace("cause", "location", "%d", param->progressinfo.location);
4692 case MESSAGE_INFORMATION:
4693 trace_header("INFORMATION", dir);
4694 if (dir == DIRECTION_OUT)
4695 add_trace("to", NULL, "CH(%lu)", port_id);
4696 if (dir == DIRECTION_IN)
4697 add_trace("from", NULL, "CH(%lu)", port_id);
4698 if (param->information.id[0])
4699 add_trace("dialing", NULL, "%s", param->information.id);
4700 if (param->information.display[0])
4701 add_trace("display", NULL, "%s", param->information.display);
4702 if (param->information.sending_complete)
4703 add_trace("complete", NULL, "true", param->information.sending_complete);
4707 case MESSAGE_FACILITY:
4708 trace_header("FACILITY", dir);
4709 if (dir == DIRECTION_OUT)
4710 add_trace("to", NULL, "CH(%lu)", port_id);
4711 if (dir == DIRECTION_IN)
4712 add_trace("from", NULL, "CH(%lu)", port_id);
4717 trace_header("TONE", dir);
4718 if (dir == DIRECTION_OUT)
4719 add_trace("to", NULL, "CH(%lu)", port_id);
4720 if (dir == DIRECTION_IN)
4721 add_trace("from", NULL, "CH(%lu)", port_id);
4722 if (param->tone.name[0]) {
4723 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4724 add_trace("name", NULL, "%s", param->tone.name);
4726 add_trace("off", NULL, NULL);
4730 case MESSAGE_SUSPEND:
4731 case MESSAGE_RESUME:
4732 if (message_type == MESSAGE_SUSPEND)
4733 trace_header("SUSPEND", dir);
4735 trace_header("RESUME", dir);
4736 if (dir == DIRECTION_OUT)
4737 add_trace("to", NULL, "CH(%lu)", port_id);
4738 if (dir == DIRECTION_IN)
4739 add_trace("from", NULL, "CH(%lu)", port_id);
4740 if (param->parkinfo.len)
4741 add_trace("length", NULL, "%d", param->parkinfo.len);
4746 case MESSAGE_BCHANNEL:
4747 trace_header("BCHANNEL", dir);
4748 switch(param->bchannel.type) {
4749 case BCHANNEL_REQUEST:
4750 add_trace("type", NULL, "request");
4752 case BCHANNEL_ASSIGN:
4753 add_trace("type", NULL, "assign");
4755 case BCHANNEL_ASSIGN_ACK:
4756 add_trace("type", NULL, "assign_ack");
4758 case BCHANNEL_REMOVE:
4759 add_trace("type", NULL, "remove");
4761 case BCHANNEL_REMOVE_ACK:
4762 add_trace("type", NULL, "remove_ack");
4765 if (param->bchannel.addr)
4766 add_trace("address", NULL, "%x", param->bchannel.addr);
4772 if (param->threepty.begin)
4773 trace_header("Begin3PTY", dir);
4774 if (param->threepty.end)
4775 trace_header("End3PTY", dir);
4776 if (param->threepty.invoke)
4777 add_trace("action", NULL, "invoke");
4778 if (param->threepty.result)
4779 add_trace("action", NULL, "result");
4780 if (param->threepty.error)
4781 add_trace("action", NULL, "error");
4782 add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id);
4786 case MESSAGE_TRANSFER:
4787 trace_header("TRANSFER", dir);
4791 case MESSAGE_DISABLE_DEJITTER:
4792 trace_header("DISBALE_DEJITTER", dir);
4794 add_trace("queue", NULL, "%d", param->queue);
4799 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4803 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4805 struct lcr_msg *message;
4809 if (!portlist->port_id)
4812 if (!e_connectedmode) {
4813 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4814 message->param.disconnectinfo.cause = cause;
4815 message->param.disconnectinfo.location = location;
4817 SCPY(message->param.disconnectinfo.display, display);
4819 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4821 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4823 SCPY(message->param.notifyinfo.display, display);
4825 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4827 message_put(message);
4828 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);