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 if (e_ext.dov_ident[0]) {
1974 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_REQUEST);
1975 SPRINT(message->param.dov.data, "%08x ", lcr_random);
1976 SCAT(message->param.dov.data, e_ext.dov_ident);
1977 message->param.dov.length = strlen((char *)message->param.dov.data);
1978 message->param.dov.type = e_ext.dov_type;
1979 message->param.dov.level = e_ext.dov_level;
1980 dov_msg_write(&message->param, 1);
1981 message_put(message);
1983 } else if (!e_adminid) {
1985 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
1986 SCPY(e_ext.number, e_cbcaller);
1987 new_state(EPOINT_STATE_IN_OVERLAP);
1988 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1990 /* get extension's info about terminal */
1991 if (!read_extension(&e_ext, e_ext.number)) {
1992 /* extension doesn't exist */
1993 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1994 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1995 new_state(EPOINT_STATE_OUT_DISCONNECT);
1996 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2000 /* put prefix in front of e_cbdialing */
2001 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2002 SCPY(e_dialinginfo.id, buffer);
2003 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2004 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2006 /* use caller id (or if exist: id_next_call) for this call */
2007 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2008 SCPY(e_callerinfo.extension, e_ext.number);
2009 if (e_ext.id_next_call_present >= 0) {
2010 SCPY(e_callerinfo.id, e_ext.id_next_call);
2011 e_callerinfo.present = e_ext.id_next_call_present;
2012 e_callerinfo.ntype = e_ext.id_next_call_type;
2013 e_ext.id_next_call_present = -1;
2014 /* extension is written */
2015 write_extension(&e_ext, e_ext.number);
2017 SCPY(e_callerinfo.id, e_ext.callerid);
2018 e_callerinfo.present = e_ext.callerid_present;
2019 e_callerinfo.ntype = e_ext.callerid_type;
2021 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2023 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2026 /* check if caller id is NOT authenticated */
2027 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2028 /* make call state to enter password */
2029 new_state(EPOINT_STATE_IN_OVERLAP);
2030 e_action = &action_password_write;
2031 unsched_timer(&e_match_timeout);
2032 e_match_to_action = NULL;
2033 e_dialinginfo.id[0] = '\0';
2034 e_extdialing = strchr(e_dialinginfo.id, '\0');
2035 schedule_timer(&e_password_timeout, 20, 0);
2038 /* incoming call (callback) */
2039 e_ruleset = ruleset_main;
2041 e_rule = e_ruleset->rule_first;
2043 e_extdialing = e_dialinginfo.id;
2044 if (e_dialinginfo.id[0]) {
2045 set_tone(portlist, "dialing");
2048 set_tone(portlist, "dialpbx");
2051 } else { /* testcall */
2052 set_tone(portlist, "hold");
2055 /* start recording if enabled, not when answering machine answers */
2056 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)) {
2057 /* check if we are a terminal */
2058 if (e_ext.number[0] == '\0')
2059 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2061 port = find_port_id(portlist->port_id);
2063 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2068 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2069 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2071 struct lcr_msg *message;
2073 unsigned int port_id = portlist->port_id;
2077 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2079 /* signal to call tool */
2080 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2082 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2083 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2084 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2089 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);
2090 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2091 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2093 /* check if we have more than one portlist relation and we just ignore the disconnect */
2094 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2095 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2096 portlist = ea_endpoint->ep_portlist;
2098 if (portlist->port_id == port_id)
2100 portlist = portlist->next;
2103 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2104 if (message_type != MESSAGE_RELEASE) {
2105 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2106 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2107 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2108 message_put(message);
2109 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2111 ea_endpoint->free_portlist(portlist);
2112 return; /* one relation removed */
2114 if (e_state == EPOINT_STATE_CONNECT) {
2115 /* use cause from port after connect */
2116 cause = param->disconnectinfo.cause;
2117 location = param->disconnectinfo.location;
2119 /* use multipoint cause if no connect yet */
2120 if (e_multipoint_cause) {
2121 cause = e_multipoint_cause;
2122 location = e_multipoint_location;
2124 cause = CAUSE_NOUSER;
2125 location = LOCATION_PRIVATE_LOCAL;
2129 unsched_timer(&e_cfnr_timeout);
2130 unsched_timer(&e_cfnr_call_timeout);
2132 /* process hangup */
2133 process_hangup(e_join_cause, e_join_location);
2134 e_multipoint_cause = 0;
2135 e_multipoint_location = 0;
2137 if (message_type == MESSAGE_DISCONNECT) {
2138 /* tone to disconnected end */
2139 SPRINT(buffer, "cause_%02x", cause);
2140 if (ea_endpoint->ep_portlist)
2141 set_tone(ea_endpoint->ep_portlist, buffer);
2143 new_state(EPOINT_STATE_IN_DISCONNECT);
2146 if (ea_endpoint->ep_join_id) {
2147 int haspatterns = 0;
2148 /* check if pattern is available */
2149 if (ea_endpoint->ep_portlist)
2150 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2151 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
2152 && message_type != MESSAGE_RELEASE) // if we release, we are done
2155 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2156 /* indicate patterns */
2157 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2158 message_put(message);
2159 /* connect audio, if not already */
2160 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2161 message->param.audiopath = 1;
2162 message_put(message);
2163 /* send disconnect */
2164 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2165 memcpy(&message->param, param, sizeof(union parameter));
2166 message_put(message);
2167 /* disable encryption if disconnected */
2168 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2171 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2175 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2178 if (message_type == MESSAGE_RELEASE)
2179 ea_endpoint->free_portlist(portlist);
2180 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2181 return; /* must exit here */
2184 /* port MESSAGE_TIMEOUT */
2185 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2189 trace_header("TIMEOUT", DIRECTION_IN);
2190 message_type = MESSAGE_DISCONNECT;
2191 switch (param->state) {
2192 case PORT_STATE_OUT_SETUP:
2193 case PORT_STATE_OUT_OVERLAP:
2194 add_trace("state", NULL, "outgoing setup/dialing");
2196 /* no user responding */
2197 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2198 return; /* must exit here */
2200 case PORT_STATE_IN_SETUP:
2201 case PORT_STATE_IN_OVERLAP:
2202 add_trace("state", NULL, "incoming setup/dialing");
2203 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2204 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2207 case PORT_STATE_OUT_PROCEEDING:
2208 add_trace("state", NULL, "outgoing proceeding");
2210 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2211 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2212 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2213 return; /* must exit here */
2215 case PORT_STATE_IN_PROCEEDING:
2216 add_trace("state", NULL, "incoming proceeding");
2217 param->disconnectinfo.cause = CAUSE_NOUSER;
2218 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2221 case PORT_STATE_OUT_ALERTING:
2222 add_trace("state", NULL, "outgoing alerting");
2224 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2225 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2226 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2227 return; /* must exit here */
2229 case PORT_STATE_CONNECT:
2230 add_trace("state", NULL, "connect");
2232 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2233 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2234 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2235 return; /* must exit here */
2237 case PORT_STATE_IN_ALERTING:
2238 add_trace("state", NULL, "incoming alerting");
2239 param->disconnectinfo.cause = CAUSE_NOANSWER;
2240 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2243 case PORT_STATE_IN_DISCONNECT:
2244 case PORT_STATE_OUT_DISCONNECT:
2245 add_trace("state", NULL, "disconnect");
2247 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2248 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2249 return; /* must exit here */
2252 param->disconnectinfo.cause = 31; /* normal unspecified */
2253 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2256 /* release call, disconnect isdn */
2258 new_state(EPOINT_STATE_OUT_DISCONNECT);
2259 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2260 SCPY(e_tone, cause);
2262 set_tone(portlist, cause);
2263 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2264 portlist = portlist->next;
2266 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2269 /* port MESSAGE_NOTIFY */
2270 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2272 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2274 struct lcr_msg *message;
2276 /* signal to call tool */
2277 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);
2278 if (param->notifyinfo.notify) {
2279 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2282 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2283 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2284 case INFO_NOTIFY_REMOTE_HOLD:
2285 case INFO_NOTIFY_USER_SUSPENDED:
2286 /* tell call about it */
2287 if (ea_endpoint->ep_join_id) {
2288 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2289 message->param.audiopath = 0;
2290 message_put(message);
2294 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2295 case INFO_NOTIFY_USER_RESUMED:
2296 /* set volume of rx and tx */
2297 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2298 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2300 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2301 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2302 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2303 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2304 message_put(message);
2306 /* set current tone */
2308 set_tone(portlist, e_tone);
2309 /* tell call about it */
2310 if (ea_endpoint->ep_join_id) {
2311 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2312 message->param.audiopath = 1;
2313 message_put(message);
2318 /* notify call if available */
2319 if (ea_endpoint->ep_join_id) {
2320 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2321 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2322 message_put(message);
2327 /* port MESSAGE_PROGRESS */
2328 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2330 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2332 struct lcr_msg *message;
2334 /* signal to call tool */
2335 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2337 /* send progress to call if available */
2338 if (ea_endpoint->ep_join_id) {
2339 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2340 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2341 message_put(message);
2346 /* port MESSAGE_FACILITY */
2347 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2349 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2351 struct lcr_msg *message;
2353 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2354 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2355 message_put(message);
2358 /* port MESSAGE_3PTY */
2359 void EndpointAppPBX::port_3pty(struct port_list *portlist, int message_type, union parameter *param)
2361 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2363 struct lcr_msg *message;
2367 if (param->threepty.begin)
2368 rc = join_3pty_dss1();
2369 else if (param->threepty.end)
2374 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_3PTY);
2375 message->param.threepty.begin = param->threepty.begin;
2376 message->param.threepty.end = param->threepty.end;
2378 message->param.threepty.error = 1;
2380 message->param.threepty.result = 1;
2381 message->param.threepty.invoke_id = param->threepty.invoke_id;
2382 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2383 message_put(message);
2386 /* port MESSAGE_TRANSFER */
2387 void EndpointAppPBX::port_transfer(struct port_list *portlist, int message_type, union parameter *param)
2389 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2393 /* bridge for real */
2394 if (!(port = find_port_id(portlist->port_id)))
2396 if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS)
2398 else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1)
2402 /* port MESSAGE_SUSPEND */
2403 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2404 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2406 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2408 /* epoint is now parked */
2409 ea_endpoint->ep_park = 1;
2410 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2411 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2413 /* remove port relation */
2414 ea_endpoint->free_portlist(portlist);
2417 /* port MESSAGE_RESUME */
2418 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2419 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2421 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2423 /* epoint is now resumed */
2424 ea_endpoint->ep_park = 0;
2428 /* port MESSAGE_ENABLEKEYPAD */
2429 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2431 struct lcr_msg *message;
2433 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2435 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2436 memcpy(&message->param, param, sizeof(union parameter));
2437 message_put(message);
2441 /* port MESSAGE_DISABLE_DEJITTER */
2442 void EndpointAppPBX::port_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
2444 struct lcr_msg *message;
2446 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2448 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DISABLE_DEJITTER);
2449 memcpy(&message->param, param, sizeof(union parameter));
2450 message_put(message);
2453 /* port MESSAGE_DOV_INDICATION */
2454 void EndpointAppPBX::port_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
2456 struct lcr_msg *message;
2458 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2460 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_INDICATION);
2461 memcpy(&message->param, param, sizeof(union parameter));
2462 message_put(message);
2466 /* port MESSAGE_UPDATEBRIDGE */
2467 void EndpointAppPBX::port_updatebridge(struct port_list *portlist, int message_type, union parameter *param)
2469 struct lcr_msg *message;
2471 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_UPDATEBRIDGE);
2472 message_put(message);
2476 /* port MESSAGE_VOOTP */
2477 void EndpointAppPBX::port_vootp(struct port_list *portlist, int message_type, union parameter *param)
2479 if (param->vootp.failed)
2480 set_tone(ea_endpoint->ep_portlist, "crypt_off");
2484 /* port sends message to the endpoint
2486 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2488 struct port_list *portlist;
2490 portlist = ea_endpoint->ep_portlist;
2492 if (port_id == portlist->port_id)
2494 portlist = portlist->next;
2497 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);
2501 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2502 switch(message_type) {
2503 case MESSAGE_TONE_EOF: /* tone is end of file */
2504 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2506 if (e_action->index == ACTION_VBOX_PLAY) {
2509 if (e_action->index == ACTION_EFI) {
2515 case MESSAGE_TONE_COUNTER: /* counter info received */
2516 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);
2518 if (e_action->index == ACTION_VBOX_PLAY) {
2519 e_vbox_counter = param->counter.current;
2520 if (param->counter.max >= 0)
2521 e_vbox_counter_max = param->counter.max;
2525 /* PORT sends SETUP message */
2527 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);
2528 if (e_state!=EPOINT_STATE_IDLE) {
2529 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2532 port_setup(portlist, message_type, param);
2535 /* PORT sends INFORMATION message */
2536 case MESSAGE_INFORMATION: /* additional digits received */
2537 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);
2538 port_information(portlist, message_type, param);
2541 /* PORT sends FACILITY message */
2542 case MESSAGE_FACILITY:
2543 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2544 port_facility(portlist, message_type, param);
2548 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming 3PTY facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2549 port_3pty(portlist, message_type, param);
2552 case MESSAGE_TRANSFER:
2553 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming TRANSFER request (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2554 port_transfer(portlist, message_type, param);
2557 /* PORT sends DTMF message */
2558 case MESSAGE_DTMF: /* dtmf digits received */
2559 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);
2560 port_dtmf(portlist, message_type, param);
2563 /* PORT sends CRYPT message */
2564 case MESSAGE_CRYPT: /* crypt response received */
2565 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2566 port_crypt(portlist, message_type, param);
2569 /* PORT sends MORE message */
2570 case MESSAGE_OVERLAP:
2571 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);
2572 if (e_state != EPOINT_STATE_OUT_SETUP) {
2573 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);
2576 port_overlap(portlist, message_type, param);
2579 /* PORT sends PROCEEDING message */
2580 case MESSAGE_PROCEEDING: /* port is proceeding */
2581 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);
2582 if (e_state!=EPOINT_STATE_OUT_SETUP
2583 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2584 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);
2587 port_proceeding(portlist, message_type, param);
2590 /* PORT sends ALERTING message */
2591 case MESSAGE_ALERTING:
2592 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);
2593 if (e_state!=EPOINT_STATE_OUT_SETUP
2594 && e_state!=EPOINT_STATE_OUT_OVERLAP
2595 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2596 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);
2599 port_alerting(portlist, message_type, param);
2602 /* PORT sends CONNECT message */
2603 case MESSAGE_CONNECT:
2604 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);
2605 if (e_state!=EPOINT_STATE_OUT_SETUP
2606 && e_state!=EPOINT_STATE_OUT_OVERLAP
2607 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2608 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2609 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2612 port_connect(portlist, message_type, param);
2615 /* PORT sends DISCONNECT message */
2616 case MESSAGE_DISCONNECT: /* port is disconnected */
2617 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);
2618 port_disconnect_release(portlist, message_type, param);
2621 /* PORT sends a RELEASE message */
2622 case MESSAGE_RELEASE: /* port releases */
2623 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);
2624 /* portlist is release at port_disconnect_release, thanx Paul */
2625 port_disconnect_release(portlist, message_type, param);
2628 /* PORT sends a TIMEOUT message */
2629 case MESSAGE_TIMEOUT:
2630 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);
2631 port_timeout(portlist, message_type, param);
2632 break; /* release */
2634 /* PORT sends a NOTIFY message */
2635 case MESSAGE_NOTIFY:
2636 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);
2637 port_notify(portlist, message_type, param);
2640 /* PORT sends a PROGRESS message */
2641 case MESSAGE_PROGRESS:
2642 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);
2643 port_progress(portlist, message_type, param);
2646 /* PORT sends a SUSPEND message */
2647 case MESSAGE_SUSPEND:
2648 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);
2649 port_suspend(portlist, message_type, param);
2650 break; /* suspend */
2652 /* PORT sends a RESUME message */
2653 case MESSAGE_RESUME:
2654 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);
2655 port_resume(portlist, message_type, param);
2659 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2660 /* port assigns bchannel */
2661 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2662 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);
2663 /* only one port is expected to be connected to bchannel */
2664 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2665 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2669 /* PORT requests DTMF */
2670 case MESSAGE_ENABLEKEYPAD:
2671 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);
2672 port_enablekeypad(portlist, message_type, param);
2675 case MESSAGE_DISABLE_DEJITTER:
2676 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);
2677 port_disable_dejitter(portlist, message_type, param);
2680 case MESSAGE_UPDATEBRIDGE:
2681 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming updatebridge message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2682 port_updatebridge(portlist, message_type, param);
2686 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming vootp message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2687 port_vootp(portlist, message_type, param);
2690 /* PORT indivated Data-Over-Voice */
2691 case MESSAGE_DOV_INDICATION:
2692 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') indicates Data-Over-Voice.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2693 port_dov_indication(portlist, message_type, param);
2697 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);
2700 /* Note: this endpoint may be destroyed, so we MUST return */
2704 /* messages from join
2706 /* join MESSAGE_CRYPT */
2707 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2710 switch(param->crypt.type) {
2711 /* message from remote port to "crypt manager" */
2712 case CU_ACTK_REQ: /* activate key-exchange */
2713 case CU_ACTS_REQ: /* activate shared key */
2714 case CU_DACT_REQ: /* deactivate */
2715 case CU_INFO_REQ: /* request last info message */
2716 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2719 /* message from "crypt manager" to user */
2720 case CU_ACTK_CONF: /* key-echange done */
2721 case CU_ACTS_CONF: /* shared key done */
2722 case CU_DACT_CONF: /* deactivated */
2723 case CU_DACT_IND: /* deactivated */
2724 case CU_ERROR_IND: /* receive error message */
2725 case CU_INFO_IND: /* receive info message */
2726 case CU_INFO_CONF: /* receive info message */
2727 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2731 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);
2736 /* join MESSAGE_INFORMATION */
2737 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2739 struct lcr_msg *message;
2744 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2745 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2746 message_put(message);
2747 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2748 portlist = portlist->next;
2752 /* join MESSAGE_FACILITY */
2753 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2755 struct lcr_msg *message;
2757 if (!e_ext.facility && e_ext.number[0]) {
2762 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2763 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2764 message_put(message);
2765 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2766 portlist = portlist->next;
2770 /* join MESSAGE_MORE */
2771 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2773 struct lcr_msg *message;
2775 new_state(EPOINT_STATE_IN_OVERLAP);
2778 if (e_join_pattern && e_ext.own_setup) {
2779 /* disconnect audio */
2780 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2781 message->param.audiopath = 0;
2782 message_put(message);
2784 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2785 if (e_dialinginfo.id[0])
2786 set_tone(portlist, "dialing");
2788 set_tone(portlist, "dialtone");
2791 if (e_dialinginfo.id[0]) {
2792 set_tone(portlist, "dialing");
2794 if (e_ext.number[0])
2795 set_tone(portlist, "dialpbx");
2797 set_tone(portlist, "dialtone");
2801 /* join MESSAGE_PROCEEDING */
2802 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2804 struct lcr_msg *message;
2806 new_state(EPOINT_STATE_IN_PROCEEDING);
2808 /* own proceeding tone */
2809 if (e_join_pattern) {
2810 /* connect / disconnect audio */
2811 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2812 if (e_ext.own_proceeding)
2813 message->param.audiopath = 0;
2815 message->param.audiopath = 1;
2816 message_put(message);
2818 // UCPY(e_join_tone, "proceeding");
2820 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2821 message_put(message);
2822 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2824 set_tone(portlist, "proceeding");
2827 /* join MESSAGE_ALERTING */
2828 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2830 struct lcr_msg *message;
2832 new_state(EPOINT_STATE_IN_ALERTING);
2834 /* own alerting tone */
2835 if (e_join_pattern) {
2836 /* connect / disconnect audio */
2837 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2838 if (e_ext.own_alerting)
2839 message->param.audiopath = 0;
2841 message->param.audiopath = 1;
2842 message_put(message);
2845 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2846 message_put(message);
2847 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2849 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2850 set_tone(portlist, "ringing");
2853 if (e_ext.number[0])
2854 set_tone(portlist, "ringpbx");
2856 set_tone(portlist, "ringing");
2858 if (e_ext.number[0])
2859 e_dtmf = 1; /* allow dtmf */
2862 /* join MESSAGE_CONNECT */
2863 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2865 struct lcr_msg *message;
2868 new_state(EPOINT_STATE_CONNECT);
2869 // UCPY(e_join_tone, "");
2871 if (e_ext.number[0])
2872 e_dtmf = 1; /* allow dtmf */
2875 unsched_timer(&e_powerdial_timeout);
2876 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2878 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2879 memcpy(&message->param, param, sizeof(union parameter));
2881 /* screen clip if prefix is required */
2882 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2883 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2884 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2885 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2888 /* use internal caller id */
2889 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2890 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2891 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2894 /* handle restricted caller ids */
2895 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);
2896 /* display callerid if desired for extension */
2897 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));
2899 /* use conp, if enabld */
2900 // if (!e_ext.centrex)
2901 // message->param.connectinfo.name[0] = '\0';
2904 message_put(message);
2905 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2907 set_tone(portlist, NULL);
2909 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2910 message->param.audiopath = 1;
2911 message_put(message);
2915 /* if the remote answered, we listen to DOV message */
2916 if (e_ext.dov_log[0]) {
2917 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_LISTEN);
2918 message->param.dov.type = e_ext.dov_type;
2919 message_put(message);
2923 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2924 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2927 struct lcr_msg *message;
2928 struct port_list *portlist = NULL;
2932 /* be sure that we are active */
2934 e_tx_state = NOTIFY_STATE_ACTIVE;
2936 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2937 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2938 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2940 /* set time for power dialing */
2941 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2944 /* set redial tone */
2945 if (ea_endpoint->ep_portlist) {
2948 set_tone(ea_endpoint->ep_portlist, "redial");
2949 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);
2950 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2951 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2952 new_state(EPOINT_STATE_IN_PROCEEDING);
2953 if (ea_endpoint->ep_portlist) {
2954 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2955 message_put(message);
2956 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2958 /* caused the error, that the first knock sound was not there */
2959 /* set_tone(portlist, "proceeding"); */
2961 /* send display of powerdialing */
2962 if (e_ext.display_dialing) {
2963 portlist = ea_endpoint->ep_portlist;
2965 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2967 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2969 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2970 message_put(message);
2971 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2972 portlist = portlist->next;
2982 if ((e_state!=EPOINT_STATE_CONNECT
2983 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2984 && e_state!=EPOINT_STATE_IN_OVERLAP
2985 && e_state!=EPOINT_STATE_IN_PROCEEDING
2986 && e_state!=EPOINT_STATE_IN_ALERTING)
2987 || !ea_endpoint->ep_portlist) { /* or no port */
2988 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2989 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2990 return; /* must exit here */
2993 if (!e_join_cause) {
2994 e_join_cause = param->disconnectinfo.cause;
2995 e_join_location = param->disconnectinfo.location;
2998 /* on release we need the audio again! */
2999 if (message_type == MESSAGE_RELEASE) {
3001 ea_endpoint->ep_join_id = 0;
3003 /* disconnect and select tone */
3004 new_state(EPOINT_STATE_OUT_DISCONNECT);
3005 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3006 /* if own_cause, we must release the join */
3007 if (e_ext.own_cause /* own cause */
3008 || !e_join_pattern) { /* no patterns */
3009 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);
3010 if (message_type != MESSAGE_RELEASE)
3011 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3013 } else { /* else we enable audio */
3014 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3015 message->param.audiopath = 1;
3016 message_put(message);
3018 /* send disconnect message */
3019 SCPY(e_tone, cause);
3020 portlist = ea_endpoint->ep_portlist;
3022 set_tone(portlist, cause);
3023 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3024 portlist = portlist->next;
3028 /* join MESSAGE_SETUP */
3029 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3031 struct lcr_msg *message;
3032 // struct interface *interface;
3034 /* if we already in setup state, we just update the dialing with new digits */
3035 if (e_state == EPOINT_STATE_OUT_SETUP
3036 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3037 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3038 /* if digits changed, what we have already dialed */
3039 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3040 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);
3041 /* release all ports */
3042 while((portlist = ea_endpoint->ep_portlist)) {
3043 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3044 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3045 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3046 message_put(message);
3047 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3048 ea_endpoint->free_portlist(portlist);
3051 /* disconnect audio */
3052 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3053 message->param.audiopath = 0;
3054 message_put(message);
3056 /* get dialing info */
3057 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3058 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3059 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3060 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3061 new_state(EPOINT_STATE_OUT_OVERLAP);
3064 schedule_timer(&e_redial_timeout, 1, 0);
3067 /* if we have a pending redial, so we just adjust the dialing number */
3068 if (e_redial_timeout.active) {
3069 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);
3070 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3073 if (!ea_endpoint->ep_portlist) {
3074 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3076 if (ea_endpoint->ep_portlist->next) {
3077 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3079 if (e_state == EPOINT_STATE_OUT_SETUP) {
3081 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);
3082 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3085 /* get what we have not dialed yet */
3086 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));
3087 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3088 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3089 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3090 message_put(message);
3091 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3093 /* always store what we have dialed or queued */
3094 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3098 if (e_state != EPOINT_STATE_IDLE) {
3099 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3102 /* if an internal extension is dialed, copy that number */
3103 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3104 SCPY(e_ext.number, param->setup.dialinginfo.id);
3105 /* if an internal extension is dialed, get extension's info about caller */
3106 if (e_ext.number[0]) {
3107 if (!read_extension(&e_ext, e_ext.number)) {
3108 e_ext.number[0] = '\0';
3109 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3113 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3114 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3115 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3116 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3117 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3119 /* process (voice over) data calls */
3120 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3121 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3122 memset(&e_capainfo, 0, sizeof(e_capainfo));
3123 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3124 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3125 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3128 new_state(EPOINT_STATE_OUT_SETUP);
3129 /* call special setup routine */
3133 /* join MESSAGE_mISDNSIGNAL */
3134 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3136 struct lcr_msg *message;
3139 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3140 memcpy(&message->param, param, sizeof(union parameter));
3141 message_put(message);
3142 portlist = portlist->next;
3146 /* join MESSAGE_BRIDE */
3147 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3149 struct lcr_msg *message;
3152 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3153 memcpy(&message->param, param, sizeof(union parameter));
3154 message_put(message);
3155 portlist = portlist->next;
3159 /* join MESSAGE_NOTIFY */
3160 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3162 struct lcr_msg *message;
3165 if (param->notifyinfo.notify) {
3166 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3167 // /* if notification was generated locally, we turn hold music on/off */
3168 // if (param->notifyinfo.local)
3169 // 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)
3173 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3174 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3176 set_tone(portlist, "");
3177 portlist = portlist->next;
3180 portlist = ea_endpoint->ep_portlist;
3185 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3187 set_tone(portlist, "hold");
3188 portlist = portlist->next;
3190 portlist = ea_endpoint->ep_portlist;
3195 /* save new state */
3196 e_tx_state = new_state;
3199 /* notify port(s) about it */
3201 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3202 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3203 /* handle restricted caller ids */
3204 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3205 /* display callerid if desired for extension */
3206 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));
3207 message_put(message);
3208 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3209 portlist = portlist->next;
3213 /* join MESSAGE_DTMF */
3214 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3216 struct lcr_msg *message;
3219 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3220 memcpy(&message->param, param, sizeof(union parameter));
3221 message_put(message);
3222 portlist = portlist->next;
3226 /* join MESSAGE_DISABLE_DEJITTER */
3227 void EndpointAppPBX::join_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
3229 struct lcr_msg *message;
3232 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISABLE_DEJITTER);
3233 memcpy(&message->param, param, sizeof(union parameter));
3234 message_put(message);
3235 portlist = portlist->next;
3239 /* join MESSAGE_DOV_INDICATION */
3240 void EndpointAppPBX::join_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
3242 dov_msg_write(param, 0);
3245 /* join MESSAGE_DOV_REQUEST */
3246 void EndpointAppPBX::join_dov_request(struct port_list *portlist, int message_type, union parameter *param)
3248 struct lcr_msg *message;
3250 /* don't send DOV from estension to extension */
3251 if (e_ext.number[0])
3255 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_REQUEST);
3256 memcpy(&message->param, param, sizeof(union parameter));
3257 message_put(message);
3258 logmessage(message_type, param, portlist->port_id, DIRECTION_OUT);
3259 portlist = portlist->next;
3263 /* join MESSAGE_DOV_LISTEN */
3264 void EndpointAppPBX::join_dov_listen(struct port_list *portlist, int message_type, union parameter *param)
3266 struct lcr_msg *message;
3269 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_LISTEN);
3270 memcpy(&message->param, param, sizeof(union parameter));
3271 message_put(message);
3272 portlist = portlist->next;
3276 /* JOIN sends messages to the endpoint
3278 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3280 struct port_list *portlist;
3281 struct lcr_msg *message;
3284 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3288 portlist = ea_endpoint->ep_portlist;
3290 // 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);
3291 switch(message_type) {
3292 /* JOIN SENDS TONE message */
3294 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);
3295 set_tone(portlist, param->tone.name);
3298 /* JOIN SENDS CRYPT message */
3300 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);
3301 join_crypt(portlist, message_type, param);
3304 /* JOIN sends INFORMATION message */
3305 case MESSAGE_INFORMATION:
3306 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);
3307 join_information(portlist, message_type, param);
3310 /* JOIN sends FACILITY message */
3311 case MESSAGE_FACILITY:
3312 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);
3313 join_facility(portlist, message_type, param);
3316 /* JOIN sends OVERLAP message */
3317 case MESSAGE_OVERLAP:
3318 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);
3319 if (e_state!=EPOINT_STATE_IN_SETUP
3320 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3321 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3324 join_overlap(portlist, message_type, param);
3327 /* JOIN sends PROCEEDING message */
3328 case MESSAGE_PROCEEDING:
3329 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);
3330 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3331 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3334 join_proceeding(portlist, message_type, param);
3337 /* JOIN sends ALERTING message */
3338 case MESSAGE_ALERTING:
3339 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);
3340 if (e_state!=EPOINT_STATE_IN_OVERLAP
3341 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3342 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3345 join_alerting(portlist, message_type, param);
3348 /* JOIN sends CONNECT message */
3349 case MESSAGE_CONNECT:
3350 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);
3351 if (e_state!=EPOINT_STATE_IN_OVERLAP
3352 && e_state!=EPOINT_STATE_IN_PROCEEDING
3353 && e_state!=EPOINT_STATE_IN_ALERTING) {
3354 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3357 join_connect(portlist, message_type, param);
3360 /* JOIN sends DISCONNECT/RELEASE message */
3361 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3362 case MESSAGE_RELEASE: /* JOIN releases */
3363 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);
3364 join_disconnect_release(message_type, param);
3367 /* JOIN sends SETUP message */
3369 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);
3370 join_setup(portlist, message_type, param);
3373 /* JOIN sends special mISDNSIGNAL message */
3374 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3375 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);
3376 join_mISDNsignal(portlist, message_type, param);
3379 /* JOIN sends bridge message */
3380 case MESSAGE_BRIDGE: /* bride message to port */
3381 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);
3382 join_bridge(portlist, message_type, param);
3385 /* JOIN has pattern available */
3386 case MESSAGE_PATTERN: /* indicating pattern available */
3387 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);
3388 if (!e_join_pattern) {
3389 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3393 set_tone(portlist, NULL);
3394 portlist = portlist->next;
3396 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3397 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3398 message->param.audiopath = 1;
3399 message_put(message);
3403 /* JOIN has no pattern available */
3404 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3405 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);
3406 if (e_join_pattern) {
3407 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3409 /* disconnect our audio tx and rx */
3410 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3411 message->param.audiopath = 0;
3412 message_put(message);
3417 /* JOIN (dunno at the moment) */
3418 case MESSAGE_REMOTE_AUDIO:
3419 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);
3420 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3421 message->param.audiopath = param->channel;
3422 message_put(message);
3426 /* JOIN sends a notify message */
3427 case MESSAGE_NOTIFY:
3428 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);
3429 join_notify(portlist, message_type, param);
3432 /* JOIN wants keypad / dtmf */
3433 case MESSAGE_ENABLEKEYPAD:
3434 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);
3437 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3441 /* JOIN sends a DTMF message */
3443 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);
3444 join_dtmf(portlist, message_type, param);
3447 /* JOIN sends a DISABLE_DEJITTER message */
3448 case MESSAGE_DISABLE_DEJITTER:
3449 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);
3450 join_disable_dejitter(portlist, message_type, param);
3453 /* JOIN sends a Data-Over-Voice message indication */
3454 case MESSAGE_DOV_INDICATION:
3455 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice indication.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3456 join_dov_indication(portlist, message_type, param);
3459 /* JOIN sends a Data-Over-Voice message request */
3460 case MESSAGE_DOV_REQUEST:
3461 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3462 join_dov_request(portlist, message_type, param);
3465 /* JOIN sends a Data-Over-Voice listen order */
3466 case MESSAGE_DOV_LISTEN:
3467 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received Data-Over-Voice listen order.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3468 join_dov_listen(portlist, message_type, param);
3472 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);
3477 /* pick_join will connect the first incoming call found. the endpoint
3478 * will receivce a MESSAGE_CONNECT.
3480 int match_list(char *list, char *item)
3482 char *end, *next = NULL;
3484 /* no list make matching */
3489 /* eliminate white spaces */
3490 while (*list > '\0' && *list <= ' ')
3496 /* if end of list is reached, we return */
3497 if (list[0] == '\0')
3499 /* if we have more than one entry (left) */
3500 if ((end = strchr(list, ',')))
3503 next = end = strchr(list, '\0');
3504 while (*(end-1) <= ' ')
3506 /* if string part matches item */
3507 if (!strncmp(list, item, end-list))
3513 void EndpointAppPBX::pick_join(char *extensions)
3515 struct lcr_msg *message;
3516 struct port_list *portlist;
3518 class EndpointAppPBX *eapp, *found;
3520 class JoinPBX *joinpbx;
3521 struct join_relation *relation;
3523 /* find an endpoint that is ringing internally or vbox with higher priority */
3525 eapp = apppbx_first;
3527 if (eapp!=this && ea_endpoint->ep_portlist) {
3528 portlist = eapp->ea_endpoint->ep_portlist;
3530 if ((port = find_port_id(portlist->port_id))) {
3531 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3532 if (match_list(extensions, eapp->e_ext.number)) {
3537 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3538 && port->p_state==PORT_STATE_OUT_ALERTING)
3539 if (match_list(extensions, eapp->e_ext.number)) {
3543 portlist = portlist->next;
3551 /* if no endpoint found */
3553 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);
3555 set_tone(ea_endpoint->ep_portlist, "cause_10");
3556 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3557 new_state(EPOINT_STATE_OUT_DISCONNECT);
3562 if (ea_endpoint->ep_join_id) {
3563 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3566 if (!eapp->ea_endpoint->ep_join_id) {
3567 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3570 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3572 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3575 if (join->j_type != JOIN_TYPE_PBX) {
3576 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3579 joinpbx = (class JoinPBX *)join;
3580 relation = joinpbx->j_relation;
3582 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3585 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3586 relation = relation->next;
3588 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3593 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3595 if (options.deb & DEBUG_EPOINT) {
3596 class Join *debug_c = join_first;
3597 class Endpoint *debug_e = epoint_first;
3598 class Port *debug_p = port_first;
3600 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3602 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3604 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3605 debug_c = debug_c->next;
3607 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3609 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3610 debug_e = debug_e->next;
3612 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3614 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3615 debug_p = debug_p->next;
3620 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3621 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3622 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3624 /* connnecting our endpoint */
3625 new_state(EPOINT_STATE_CONNECT);
3626 if (e_ext.number[0])
3628 set_tone(ea_endpoint->ep_portlist, NULL);
3630 /* now we send a release to the ringing endpoint */
3631 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3632 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3633 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3634 message_put(message);
3636 /* we send a connect to the join with our caller id */
3637 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3638 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3639 message->param.connectinfo.present = e_callerinfo.present;
3640 message->param.connectinfo.screen = e_callerinfo.screen;
3641 message->param.connectinfo.itype = e_callerinfo.itype;
3642 message->param.connectinfo.ntype = e_callerinfo.ntype;
3643 message_put(message);
3645 /* we send a connect to our port with the remote callerid */
3646 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3647 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3648 message->param.connectinfo.present = eapp->e_callerinfo.present;
3649 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3650 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3651 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3652 /* handle restricted caller ids */
3653 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);
3654 /* display callerid if desired for extension */
3655 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));
3656 message_put(message);
3658 /* we send a connect to the audio path (not for vbox) */
3659 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3660 message->param.audiopath = 1;
3661 message_put(message);
3663 /* beeing paranoid, we make call update */
3664 trigger_work(&joinpbx->j_updatebridge);
3666 if (options.deb & DEBUG_EPOINT) {
3667 class Join *debug_c = join_first;
3668 class Endpoint *debug_e = epoint_first;
3669 class Port *debug_p = port_first;
3671 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3673 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3675 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3676 debug_c = debug_c->next;
3678 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3680 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3681 debug_e = debug_e->next;
3683 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3685 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3686 debug_p = debug_p->next;
3692 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3694 int EndpointAppPBX::join_join_dss1(void)
3697 struct lcr_msg *message;
3698 struct join_relation *add_relation, *remove_relation;
3699 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3700 class Join *our_join, *other_join, *add_join, *remove_join;
3701 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3702 class EndpointAppPBX *other_eapp, *remove_eapp;
3703 class Port *our_port, *other_port;
3704 class Pdss1 *our_pdss1, *other_pdss1;
3705 class Endpoint *temp_epoint;
3707 /* are we a candidate to join a join? */
3708 our_join = find_join_id(ea_endpoint->ep_join_id);
3710 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3713 if (our_join->j_type != JOIN_TYPE_PBX) {
3714 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3717 our_joinpbx = (class JoinPBX *)our_join;
3718 if (!ea_endpoint->ep_portlist) {
3719 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3722 if (!e_ext.number[0]) {
3723 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3726 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3728 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3731 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3732 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3735 our_pdss1 = (class Pdss1 *)our_port;
3737 /* find an endpoint that has the same mISDNport/ces that we are on */
3738 other_eapp = apppbx_first;
3740 if (other_eapp == this) {
3741 other_eapp = other_eapp->next;
3744 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);
3745 if (other_eapp->e_ext.number[0] /* has terminal */
3746 && other_eapp->ea_endpoint->ep_portlist /* has port */
3747 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3748 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3749 if (other_port) { /* port still exists */
3750 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3751 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3752 other_pdss1 = (class Pdss1 *)other_port;
3753 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);
3754 if (1 //other_pdss1->p_m_hold /* port is on hold */
3755 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3756 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3759 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3762 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3765 other_eapp = other_eapp->next;
3768 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3771 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3773 /* if we have the same join */
3774 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3775 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3778 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3780 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3783 if (other_join->j_type != JOIN_TYPE_PBX) {
3784 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3787 other_joinpbx = (class JoinPBX *)other_join;
3788 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3789 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3793 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3794 if (our_pdss1->p_m_hold && !other_pdss1->p_m_hold) {
3795 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);
3797 remove_join = our_join;
3798 remove_joinpbx = our_joinpbx;
3799 add_join = other_join;
3800 add_joinpbx = other_joinpbx;
3802 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);
3803 remove_eapp = other_eapp;
3804 remove_join = other_join;
3805 remove_joinpbx = other_joinpbx;
3806 add_join = our_join;
3807 add_joinpbx = our_joinpbx;
3810 /* remove relation to endpoint for join on hold */
3811 remove_relation = remove_joinpbx->j_relation;
3812 remove_relation_pointer = &remove_joinpbx->j_relation;
3813 while(remove_relation) {
3814 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3815 /* detach other endpoint */
3816 *remove_relation_pointer = remove_relation->next;
3817 FREE(remove_relation, sizeof(struct join_relation));
3819 remove_relation = *remove_relation_pointer;
3820 remove_eapp->ea_endpoint->ep_join_id = 0;
3824 /* change join/hold pointer of endpoint to the new join */
3825 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3827 if (temp_epoint->ep_join_id == remove_join->j_serial)
3828 temp_epoint->ep_join_id = add_join->j_serial;
3831 remove_relation_pointer = &remove_relation->next;
3832 remove_relation = remove_relation->next;
3834 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3836 /* join call relations */
3837 add_relation = add_joinpbx->j_relation;
3838 add_relation_pointer = &add_joinpbx->j_relation;
3839 while(add_relation) {
3840 add_relation_pointer = &add_relation->next;
3841 add_relation = add_relation->next;
3843 *add_relation_pointer = remove_joinpbx->j_relation;
3844 remove_joinpbx->j_relation = NULL;
3845 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3847 /* release endpoint */
3848 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3849 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3850 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3851 message_put(message);
3853 /* if we are not a partyline, we get partyline state from other join */
3854 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3856 /* remove empty join */
3858 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3860 /* mixer must update */
3861 trigger_work(&add_joinpbx->j_updatebridge);
3863 /* we send a retrieve to that endpoint */
3864 // mixer will update the hold-state of the join and send it to the endpoints is changes
3866 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3872 /* join calls (look for a join that is on hold (same fxs interface/terminal))
3874 int EndpointAppPBX::join_join_fxs(void)
3877 struct lcr_msg *message;
3878 struct join_relation *add_relation, *remove_relation;
3879 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3880 class Join *our_join, *other_join, *add_join, *remove_join;
3881 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3882 class EndpointAppPBX *other_eapp, *remove_eapp;
3883 class Port *our_port, *other_port;
3884 class Pfxs *our_fxs, *other_fxs;
3885 class Endpoint *temp_epoint;
3887 /* are we a candidate to join a join? */
3888 our_join = find_join_id(ea_endpoint->ep_join_id);
3890 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3893 if (our_join->j_type != JOIN_TYPE_PBX) {
3894 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3897 our_joinpbx = (class JoinPBX *)our_join;
3898 if (!ea_endpoint->ep_portlist) {
3899 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3902 if (!e_ext.number[0]) {
3903 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3906 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3908 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3911 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
3912 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not fxs.\n", ea_endpoint->ep_serial);
3915 our_fxs = (class Pfxs *)our_port;
3917 /* find an endpoint that has the same mISDNport that we are on */
3918 other_eapp = apppbx_first;
3920 if (other_eapp == this) {
3921 other_eapp = other_eapp->next;
3924 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);
3925 if (other_eapp->e_ext.number[0] /* has terminal */
3926 && other_eapp->ea_endpoint->ep_portlist /* has port */
3927 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3928 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3929 if (other_port) { /* port still exists */
3930 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
3931 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is FXS */
3932 other_fxs = (class Pfxs *)other_port;
3933 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);
3934 if (1 //other_fxs->p_m_hold /* port is on hold */
3935 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
3938 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3941 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3944 other_eapp = other_eapp->next;
3947 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
3950 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3952 /* if we have the same join */
3953 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3954 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3957 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3959 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3962 if (other_join->j_type != JOIN_TYPE_PBX) {
3963 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3966 other_joinpbx = (class JoinPBX *)other_join;
3967 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3968 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3972 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3973 if (our_fxs->p_m_hold && !other_fxs->p_m_hold) {
3974 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);
3976 remove_join = our_join;
3977 remove_joinpbx = our_joinpbx;
3978 add_join = other_join;
3979 add_joinpbx = other_joinpbx;
3981 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);
3982 remove_eapp = other_eapp;
3983 remove_join = other_join;
3984 remove_joinpbx = other_joinpbx;
3985 add_join = our_join;
3986 add_joinpbx = our_joinpbx;
3989 /* remove relation to endpoint for join on hold */
3990 remove_relation = remove_joinpbx->j_relation;
3991 remove_relation_pointer = &remove_joinpbx->j_relation;
3992 while(remove_relation) {
3993 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
3994 /* detach other endpoint */
3995 *remove_relation_pointer = remove_relation->next;
3996 FREE(remove_relation, sizeof(struct join_relation));
3998 remove_relation = *remove_relation_pointer;
3999 remove_eapp->ea_endpoint->ep_join_id = 0;
4003 /* change join/hold pointer of endpoint to the new join */
4004 temp_epoint = find_epoint_id(remove_relation->epoint_id);
4006 if (temp_epoint->ep_join_id == remove_join->j_serial)
4007 temp_epoint->ep_join_id = add_join->j_serial;
4010 remove_relation_pointer = &remove_relation->next;
4011 remove_relation = remove_relation->next;
4013 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
4015 /* join call relations */
4016 add_relation = add_joinpbx->j_relation;
4017 add_relation_pointer = &add_joinpbx->j_relation;
4018 while(add_relation) {
4019 add_relation_pointer = &add_relation->next;
4020 add_relation = add_relation->next;
4022 *add_relation_pointer = remove_joinpbx->j_relation;
4023 remove_joinpbx->j_relation = NULL;
4024 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
4026 /* release endpoint */
4027 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
4028 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
4029 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
4030 message_put(message);
4032 /* if we are not a partyline, we get partyline state from other join */
4033 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
4035 /* remove empty join */
4037 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
4039 /* mixer must update */
4040 trigger_work(&add_joinpbx->j_updatebridge);
4042 /* we send a retrieve to that endpoint */
4043 // mixer will update the hold-state of the join and send it to the endpoints is changes
4045 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4051 int EndpointAppPBX::join_3pty_dss1(void)
4054 class Join *our_join, *other_join;
4055 class JoinPBX *our_joinpbx, *other_joinpbx;
4056 class EndpointAppPBX *other_eapp;
4057 class Port *our_port, *other_port;
4058 class Pdss1 *our_pdss1, *other_pdss1;
4060 /* are we a candidate to join a join? */
4061 our_join = find_join_id(ea_endpoint->ep_join_id);
4063 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4066 if (our_join->j_type != JOIN_TYPE_PBX) {
4067 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4070 our_joinpbx = (class JoinPBX *)our_join;
4071 if (!ea_endpoint->ep_portlist) {
4072 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4075 if (!e_ext.number[0]) {
4076 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4079 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4081 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4084 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
4085 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
4088 our_pdss1 = (class Pdss1 *)our_port;
4090 /* find an endpoint that has the same mISDNport/ces that we are on */
4091 other_eapp = apppbx_first;
4093 if (other_eapp == this) {
4094 other_eapp = other_eapp->next;
4097 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);
4098 if (other_eapp->e_ext.number[0] /* has terminal */
4099 && other_eapp->ea_endpoint->ep_portlist /* has port */
4100 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4101 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4102 if (other_port) { /* port still exists */
4103 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
4104 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
4105 other_pdss1 = (class Pdss1 *)other_port;
4106 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);
4107 if (1 //other_pdss1->p_m_hold /* port is on hold */
4108 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
4109 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
4112 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4115 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4118 other_eapp = other_eapp->next;
4121 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
4124 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4126 /* if we have the same join */
4127 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4128 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4131 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4133 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4136 if (other_join->j_type != JOIN_TYPE_PBX) {
4137 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4140 other_joinpbx = (class JoinPBX *)other_join;
4141 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4142 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4146 if (our_joinpbx->j_3pty) {
4147 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4150 if (other_joinpbx->j_3pty) {
4151 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4155 /* set 3PTY bridge */
4156 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4157 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4159 /* mixer must update */
4160 trigger_work(&our_joinpbx->j_updatebridge);
4161 trigger_work(&other_joinpbx->j_updatebridge);
4163 /* we send a retrieve to that endpoint */
4164 // mixer will update the hold-state of the join and send it to the endpoints is changes
4166 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4172 int EndpointAppPBX::join_3pty_fxs(void)
4175 class Join *our_join, *other_join;
4176 class JoinPBX *our_joinpbx, *other_joinpbx;
4177 class EndpointAppPBX *other_eapp;
4178 class Port *our_port, *other_port;
4179 class Pfxs *our_fxs, *other_fxs;
4181 /* are we a candidate to join a join? */
4182 our_join = find_join_id(ea_endpoint->ep_join_id);
4184 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4187 if (our_join->j_type != JOIN_TYPE_PBX) {
4188 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4191 our_joinpbx = (class JoinPBX *)our_join;
4192 if (!ea_endpoint->ep_portlist) {
4193 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4196 if (!e_ext.number[0]) {
4197 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4200 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4202 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4205 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
4206 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not FXS pots.\n", ea_endpoint->ep_serial);
4209 our_fxs = (class Pfxs *)our_port;
4211 /* find an endpoint that has the same mISDNport that we are on */
4212 other_eapp = apppbx_first;
4214 if (other_eapp == this) {
4215 other_eapp = other_eapp->next;
4218 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);
4219 if (other_eapp->e_ext.number[0] /* has terminal */
4220 && other_eapp->ea_endpoint->ep_portlist /* has port */
4221 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4222 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4223 if (other_port) { /* port still exists */
4224 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4225 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is isdn nt-mode */
4226 other_fxs = (class Pfxs *)other_port;
4227 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);
4228 if (1 //other_fxs->p_m_hold /* port is on hold */
4229 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
4232 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4235 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4238 other_eapp = other_eapp->next;
4241 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4244 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4246 /* if we have the same join */
4247 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4248 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4251 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4253 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4256 if (other_join->j_type != JOIN_TYPE_PBX) {
4257 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4260 other_joinpbx = (class JoinPBX *)other_join;
4261 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4262 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4266 if (our_joinpbx->j_3pty) {
4267 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4270 if (other_joinpbx->j_3pty) {
4271 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4275 /* set 3PTY bridge */
4276 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4277 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4279 /* mixer must update */
4280 trigger_work(&our_joinpbx->j_updatebridge);
4281 trigger_work(&other_joinpbx->j_updatebridge);
4283 /* we send a retrieve to that endpoint */
4284 // mixer will update the hold-state of the join and send it to the endpoints is changes
4286 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4292 int EndpointAppPBX::split_3pty(void)
4295 class Join *our_join, *other_join;
4296 class JoinPBX *our_joinpbx, *other_joinpbx;
4298 /* are we a candidate to join a join? */
4299 our_join = find_join_id(ea_endpoint->ep_join_id);
4301 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4304 if (our_join->j_type != JOIN_TYPE_PBX) {
4305 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4308 our_joinpbx = (class JoinPBX *)our_join;
4310 if (!our_joinpbx->j_3pty) {
4311 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
4315 other_join = find_join_id(our_joinpbx->j_3pty);
4317 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4320 if (other_join->j_type != JOIN_TYPE_PBX) {
4321 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4324 other_joinpbx = (class JoinPBX *)other_join;
4326 our_joinpbx->j_3pty = 0;
4327 other_joinpbx->j_3pty = 0;
4329 /* mixer must update */
4330 trigger_work(&our_joinpbx->j_updatebridge);
4331 trigger_work(&other_joinpbx->j_updatebridge);
4333 /* we send a retrieve to that endpoint */
4334 // mixer will update the hold-state of the join and send it to the endpoints is changes
4336 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4342 /* check if we have an external call
4343 * this is used to check for encryption ability
4345 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
4347 struct join_relation *relation;
4349 class JoinPBX *joinpbx;
4350 class Endpoint *epoint;
4352 /* some paranoia check */
4353 if (!ea_endpoint->ep_portlist) {
4354 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4355 *errstr = "No Call";
4358 if (!e_ext.number[0]) {
4359 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4360 *errstr = "No Call";
4364 /* check if we have a join with 2 parties */
4365 join = find_join_id(ea_endpoint->ep_join_id);
4367 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
4368 *errstr = "No Call";
4371 if (join->j_type != JOIN_TYPE_PBX) {
4372 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4373 *errstr = "No PBX Call";
4376 joinpbx = (class JoinPBX *)join;
4377 relation = joinpbx->j_relation;
4379 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4380 *errstr = "No Call";
4383 if (!relation->next) {
4384 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4385 *errstr = "No Call";
4388 if (relation->next->next) {
4389 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4390 *errstr = "Err: Conference";
4393 if (relation->epoint_id == ea_endpoint->ep_serial) {
4394 relation = relation->next;
4395 if (relation->epoint_id == ea_endpoint->ep_serial) {
4396 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4397 *errstr = "Software Error";
4402 /* check remote port for external call */
4403 epoint = find_epoint_id(relation->epoint_id);
4405 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4406 *errstr = "No Call";
4409 if (!epoint->ep_portlist) {
4410 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4411 *errstr = "No Call";
4414 *port = find_port_id(epoint->ep_portlist->port_id);
4416 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4417 *errstr = "No Call";
4420 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4421 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4422 *errstr = "No Ext Call";
4425 if ((*port)->p_state != PORT_STATE_CONNECT) {
4426 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4427 *errstr = "No Ext Connect";
4433 int EndpointAppPBX::vootp_on(int on)
4436 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4438 if (!e_ext.otp_ident[0]) {
4439 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4442 if(ea_endpoint->ep_portlist) {
4443 struct lcr_msg *message;
4445 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VOOTP);
4446 message->param.vootp.enable = on;
4447 SCPY(message->param.vootp.id, e_ext.otp_ident);
4448 message_put(message);
4451 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4457 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4459 const char *logtext = "unknown";
4462 switch(message_type) {
4464 trace_header("SETUP", dir);
4465 if (dir == DIRECTION_OUT)
4466 add_trace("to", NULL, "CH(%lu)", port_id);
4467 if (dir == DIRECTION_IN)
4468 add_trace("from", NULL, "CH(%lu)", port_id);
4469 if (param->setup.callerinfo.extension[0])
4470 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4471 if (param->setup.callerinfo.interface[0])
4472 add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
4473 if (param->setup.dialinginfo.interfaces[0])
4474 add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
4475 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4476 switch(param->setup.callerinfo.present) {
4477 case INFO_PRESENT_RESTRICTED:
4478 add_trace("caller id", "present", "restricted");
4480 case INFO_PRESENT_ALLOWED:
4481 add_trace("caller id", "present", "allowed");
4484 add_trace("caller id", "present", "not available");
4486 if (param->setup.callerinfo.ntype2) {
4487 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4488 switch(param->setup.callerinfo.present) {
4489 case INFO_PRESENT_RESTRICTED:
4490 add_trace("caller id2", "present", "restricted");
4492 case INFO_PRESENT_ALLOWED:
4493 add_trace("caller id2", "present", "allowed");
4496 add_trace("caller id2", "present", "not available");
4499 if (param->setup.redirinfo.id[0]) {
4500 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4501 switch(param->setup.redirinfo.present) {
4502 case INFO_PRESENT_RESTRICTED:
4503 add_trace("redir'ing", "present", "restricted");
4505 case INFO_PRESENT_ALLOWED:
4506 add_trace("redir'ing", "present", "allowed");
4509 add_trace("redir'ing", "present", "not available");
4512 if (param->setup.dialinginfo.id[0])
4513 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4514 if (param->setup.dialinginfo.keypad[0])
4515 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4516 if (param->setup.dialinginfo.display[0])
4517 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4518 if (param->setup.dialinginfo.sending_complete)
4519 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4523 case MESSAGE_OVERLAP:
4524 trace_header("SETUP ACKNOWLEDGE", dir);
4525 if (dir == DIRECTION_OUT)
4526 add_trace("to", NULL, "CH(%lu)", port_id);
4527 if (dir == DIRECTION_IN)
4528 add_trace("from", NULL, "CH(%lu)", port_id);
4532 case MESSAGE_PROCEEDING:
4533 trace_header("PROCEEDING", dir);
4534 if (dir == DIRECTION_OUT)
4535 add_trace("to", NULL, "CH(%lu)", port_id);
4536 if (dir == DIRECTION_IN)
4537 add_trace("from", NULL, "CH(%lu)", port_id);
4541 case MESSAGE_ALERTING:
4542 trace_header("ALERTING", dir);
4543 if (dir == DIRECTION_OUT)
4544 add_trace("to", NULL, "CH(%lu)", port_id);
4545 if (dir == DIRECTION_IN)
4546 add_trace("from", NULL, "CH(%lu)", port_id);
4550 case MESSAGE_CONNECT:
4551 trace_header("CONNECT", dir);
4552 if (dir == DIRECTION_OUT)
4553 add_trace("to", NULL, "CH(%lu)", port_id);
4554 if (dir == DIRECTION_IN)
4555 add_trace("from", NULL, "CH(%lu)", port_id);
4556 if (param->connectinfo.extension[0])
4557 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4558 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4559 switch(param->connectinfo.present) {
4560 case INFO_PRESENT_RESTRICTED:
4561 add_trace("connect id", "present", "restricted");
4563 case INFO_PRESENT_ALLOWED:
4564 add_trace("connect id", "present", "allowed");
4567 add_trace("connect id", "present", "not available");
4569 if (param->connectinfo.display[0])
4570 add_trace("display", NULL, "%s", param->connectinfo.display);
4574 case MESSAGE_DISCONNECT:
4575 case MESSAGE_RELEASE:
4576 if (message_type == MESSAGE_DISCONNECT)
4577 trace_header("DISCONNECT", dir);
4579 trace_header("RELEASE", dir);
4580 if (dir == DIRECTION_OUT)
4581 add_trace("to", NULL, "CH(%lu)", port_id);
4582 if (dir == DIRECTION_IN)
4583 add_trace("from", NULL, "CH(%lu)", port_id);
4584 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4585 switch(param->disconnectinfo.location) {
4587 add_trace("cause", "location", "0-User");
4589 case LOCATION_PRIVATE_LOCAL:
4590 add_trace("cause", "location", "1-Local-PBX");
4592 case LOCATION_PUBLIC_LOCAL:
4593 add_trace("cause", "location", "2-Local-Exchange");
4595 case LOCATION_TRANSIT:
4596 add_trace("cause", "location", "3-Transit");
4598 case LOCATION_PUBLIC_REMOTE:
4599 add_trace("cause", "location", "4-Remote-Exchange");
4601 case LOCATION_PRIVATE_REMOTE:
4602 add_trace("cause", "location", "5-Remote-PBX");
4604 case LOCATION_INTERNATIONAL:
4605 add_trace("cause", "location", "7-International-Exchange");
4607 case LOCATION_BEYOND:
4608 add_trace("cause", "location", "10-Beyond-Interworking");
4611 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4613 if (param->disconnectinfo.display[0])
4614 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4618 case MESSAGE_NOTIFY:
4619 switch(param->notifyinfo.notify) {
4624 logtext = "USER_SUSPENDED";
4627 logtext = "BEARER_SERVICE_CHANGED";
4630 logtext = "USER_RESUMED";
4633 logtext = "CONFERENCE_ESTABLISHED";
4636 logtext = "CONFERENCE_DISCONNECTED";
4639 logtext = "OTHER_PARTY_ADDED";
4642 logtext = "ISOLATED";
4645 logtext = "REATTACHED";
4648 logtext = "OTHER_PARTY_ISOLATED";
4651 logtext = "OTHER_PARTY_REATTACHED";
4654 logtext = "OTHER_PARTY_SPLIT";
4657 logtext = "OTHER_PARTY_DISCONNECTED";
4660 logtext = "CONFERENCE_FLOATING";
4663 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4666 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4669 logtext = "CALL_IS_A_WAITING_CALL";
4672 logtext = "DIVERSION_ACTIVATED";
4675 logtext = "RESERVED_CT_1";
4678 logtext = "RESERVED_CT_2";
4681 logtext = "REVERSE_CHARGING";
4684 logtext = "REMOTE_HOLD";
4687 logtext = "REMOTE_RETRIEVAL";
4690 logtext = "CALL_IS_DIVERTING";
4693 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4697 trace_header("NOTIFY", dir);
4698 if (dir == DIRECTION_OUT)
4699 add_trace("to", NULL, "CH(%lu)", port_id);
4700 if (dir == DIRECTION_IN)
4701 add_trace("from", NULL, "CH(%lu)", port_id);
4702 if (param->notifyinfo.notify)
4703 add_trace("indicator", NULL, "%s", logtext);
4704 if (param->notifyinfo.id[0]) {
4705 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4706 switch(param->notifyinfo.present) {
4707 case INFO_PRESENT_RESTRICTED:
4708 add_trace("redir'on", "present", "restricted");
4710 case INFO_PRESENT_ALLOWED:
4711 add_trace("redir'on", "present", "allowed");
4714 add_trace("redir'on", "present", "not available");
4717 if (param->notifyinfo.display[0])
4718 add_trace("display", NULL, "%s", param->notifyinfo.display);
4722 case MESSAGE_PROGRESS:
4723 switch(param->progressinfo.progress) {
4725 logtext = "Call is not end to end ISDN";
4728 logtext = "Destination address is non-ISDN";
4731 logtext = "Origination address is non-ISDN";
4734 logtext = "Call has returned to the ISDN";
4737 logtext = "In-band info or pattern available";
4740 SPRINT(buffer, "%d", param->progressinfo.progress);
4744 trace_header("PROGRESS", dir);
4745 if (dir == DIRECTION_OUT)
4746 add_trace("to", NULL, "CH(%lu)", port_id);
4747 if (dir == DIRECTION_IN)
4748 add_trace("from", NULL, "CH(%lu)", port_id);
4749 add_trace("indicator", NULL, "%s", logtext);
4750 switch(param->progressinfo.location) {
4752 add_trace("cause", "location", "0-User");
4754 case LOCATION_PRIVATE_LOCAL:
4755 add_trace("cause", "location", "1-Local-PBX");
4757 case LOCATION_PUBLIC_LOCAL:
4758 add_trace("cause", "location", "2-Local-Exchange");
4760 case LOCATION_TRANSIT:
4761 add_trace("cause", "location", "3-Transit");
4763 case LOCATION_PUBLIC_REMOTE:
4764 add_trace("cause", "location", "4-Remote-Exchange");
4766 case LOCATION_PRIVATE_REMOTE:
4767 add_trace("cause", "location", "5-Remote-PBX");
4769 case LOCATION_INTERNATIONAL:
4770 add_trace("cause", "location", "7-International-Exchange");
4772 case LOCATION_BEYOND:
4773 add_trace("cause", "location", "10-Beyond-Interworking");
4776 add_trace("cause", "location", "%d", param->progressinfo.location);
4781 case MESSAGE_INFORMATION:
4782 trace_header("INFORMATION", dir);
4783 if (dir == DIRECTION_OUT)
4784 add_trace("to", NULL, "CH(%lu)", port_id);
4785 if (dir == DIRECTION_IN)
4786 add_trace("from", NULL, "CH(%lu)", port_id);
4787 if (param->information.id[0])
4788 add_trace("dialing", NULL, "%s", param->information.id);
4789 if (param->information.display[0])
4790 add_trace("display", NULL, "%s", param->information.display);
4791 if (param->information.sending_complete)
4792 add_trace("complete", NULL, "true", param->information.sending_complete);
4796 case MESSAGE_FACILITY:
4797 trace_header("FACILITY", dir);
4798 if (dir == DIRECTION_OUT)
4799 add_trace("to", NULL, "CH(%lu)", port_id);
4800 if (dir == DIRECTION_IN)
4801 add_trace("from", NULL, "CH(%lu)", port_id);
4806 trace_header("TONE", dir);
4807 if (dir == DIRECTION_OUT)
4808 add_trace("to", NULL, "CH(%lu)", port_id);
4809 if (dir == DIRECTION_IN)
4810 add_trace("from", NULL, "CH(%lu)", port_id);
4811 if (param->tone.name[0]) {
4812 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4813 add_trace("name", NULL, "%s", param->tone.name);
4815 add_trace("off", NULL, NULL);
4819 case MESSAGE_SUSPEND:
4820 case MESSAGE_RESUME:
4821 if (message_type == MESSAGE_SUSPEND)
4822 trace_header("SUSPEND", dir);
4824 trace_header("RESUME", dir);
4825 if (dir == DIRECTION_OUT)
4826 add_trace("to", NULL, "CH(%lu)", port_id);
4827 if (dir == DIRECTION_IN)
4828 add_trace("from", NULL, "CH(%lu)", port_id);
4829 if (param->parkinfo.len)
4830 add_trace("length", NULL, "%d", param->parkinfo.len);
4835 case MESSAGE_BCHANNEL:
4836 trace_header("BCHANNEL", dir);
4837 switch(param->bchannel.type) {
4838 case BCHANNEL_REQUEST:
4839 add_trace("type", NULL, "request");
4841 case BCHANNEL_ASSIGN:
4842 add_trace("type", NULL, "assign");
4844 case BCHANNEL_ASSIGN_ACK:
4845 add_trace("type", NULL, "assign_ack");
4847 case BCHANNEL_REMOVE:
4848 add_trace("type", NULL, "remove");
4850 case BCHANNEL_REMOVE_ACK:
4851 add_trace("type", NULL, "remove_ack");
4854 if (param->bchannel.addr)
4855 add_trace("address", NULL, "%x", param->bchannel.addr);
4861 if (param->threepty.begin)
4862 trace_header("Begin3PTY", dir);
4863 if (param->threepty.end)
4864 trace_header("End3PTY", dir);
4865 if (param->threepty.invoke)
4866 add_trace("action", NULL, "invoke");
4867 if (param->threepty.result)
4868 add_trace("action", NULL, "result");
4869 if (param->threepty.error)
4870 add_trace("action", NULL, "error");
4871 add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id);
4875 case MESSAGE_TRANSFER:
4876 trace_header("TRANSFER", dir);
4880 case MESSAGE_DISABLE_DEJITTER:
4881 trace_header("DISBALE_DEJITTER", dir);
4883 add_trace("queue", NULL, "%d", param->queue);
4887 case MESSAGE_DOV_INDICATION:
4888 case MESSAGE_DOV_REQUEST:
4889 trace_header("Data-Over-Voice", dir);
4890 if (dir == DIRECTION_OUT)
4891 add_trace("to", NULL, "CH(%lu)", port_id);
4892 if (dir == DIRECTION_IN)
4893 add_trace("from", NULL, "CH(%lu)", port_id);
4895 char dov_str[param->dov.length + 1];
4896 memcpy(dov_str, param->dov.data, param->dov.length);
4897 dov_str[param->dov.length] = '\0';
4898 add_trace("string", NULL, "%s", dov_str);
4900 add_trace("type", NULL, "%d", param->dov.type);
4905 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4909 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4911 struct lcr_msg *message;
4915 if (!portlist->port_id)
4918 if (!e_connectedmode) {
4919 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4920 message->param.disconnectinfo.cause = cause;
4921 message->param.disconnectinfo.location = location;
4923 SCPY(message->param.disconnectinfo.display, display);
4925 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4927 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4929 SCPY(message->param.notifyinfo.display, display);
4931 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4933 message_put(message);
4934 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
4937 void EndpointAppPBX::dov_msg_write(union parameter *param, int sent)
4942 int __attribute__((__unused__)) rc;
4944 /* no write, if no log file given */
4945 if (!e_ext.dov_log[0])
4948 fp = fopen(e_ext.dov_log, "a");
4950 PERROR("EPOINT(%d) failed to open Data-Over-Voice log file '%s'\n", ea_endpoint->ep_serial, e_ext.dov_log);
4955 tm = localtime(&ti);
4956 fprintf(fp, "%02d.%02d.%02d %02d:%02d:%02d ", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100, tm->tm_hour, tm->tm_min, tm->tm_sec);
4960 fprintf(fp, "sent [%s] ", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
4962 fprintf(fp, "received [%s] ", e_dialinginfo.id);
4965 rc = fwrite(param->dov.data, param->dov.length, 1, fp);