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, "", NULL);
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, "", NULL);
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, "", NULL);
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, "", NULL);
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);
2392 struct lcr_msg *message;
2395 /* bridge for real */
2396 if (!(port = find_port_id(portlist->port_id)))
2398 if ((port->p_type & PORT_CLASS_POTS_MASK) == PORT_CLASS_POTS_FXS)
2400 else if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1
2401 || (port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) {
2402 rc = join_join_dss1(param->transfer.invoke_id);
2405 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TRANSFER);
2406 message->param.transfer.error = 1;
2407 message->param.transfer.invoke_id = param->transfer.invoke_id;
2408 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2409 message_put(message);
2414 /* port MESSAGE_SUSPEND */
2415 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2416 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2418 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2420 /* epoint is now parked */
2421 ea_endpoint->ep_park = 1;
2422 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2423 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2425 /* remove port relation */
2426 ea_endpoint->free_portlist(portlist);
2429 /* port MESSAGE_RESUME */
2430 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2431 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2433 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2435 /* epoint is now resumed */
2436 ea_endpoint->ep_park = 0;
2440 /* port MESSAGE_ENABLEKEYPAD */
2441 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2443 struct lcr_msg *message;
2445 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2447 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2448 memcpy(&message->param, param, sizeof(union parameter));
2449 message_put(message);
2453 /* port MESSAGE_DISABLE_DEJITTER */
2454 void EndpointAppPBX::port_disable_dejitter(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_DISABLE_DEJITTER);
2461 memcpy(&message->param, param, sizeof(union parameter));
2462 message_put(message);
2465 /* port MESSAGE_DOV_INDICATION */
2466 void EndpointAppPBX::port_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
2468 struct lcr_msg *message;
2470 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2472 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_INDICATION);
2473 memcpy(&message->param, param, sizeof(union parameter));
2474 message_put(message);
2478 /* port MESSAGE_UPDATEBRIDGE */
2479 void EndpointAppPBX::port_updatebridge(struct port_list *portlist, int message_type, union parameter *param)
2481 struct lcr_msg *message;
2483 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_UPDATEBRIDGE);
2484 message_put(message);
2488 /* port MESSAGE_VOOTP */
2489 void EndpointAppPBX::port_vootp(struct port_list *portlist, int message_type, union parameter *param)
2491 if (param->vootp.failed)
2492 set_tone(ea_endpoint->ep_portlist, "crypt_off");
2496 /* port sends message to the endpoint
2498 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2500 struct port_list *portlist;
2502 portlist = ea_endpoint->ep_portlist;
2504 if (port_id == portlist->port_id)
2506 portlist = portlist->next;
2509 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);
2513 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2514 switch(message_type) {
2515 case MESSAGE_TONE_EOF: /* tone is end of file */
2516 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2518 if (e_action->index == ACTION_VBOX_PLAY) {
2521 if (e_action->index == ACTION_EFI) {
2527 case MESSAGE_TONE_COUNTER: /* counter info received */
2528 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);
2530 if (e_action->index == ACTION_VBOX_PLAY) {
2531 e_vbox_counter = param->counter.current;
2532 if (param->counter.max >= 0)
2533 e_vbox_counter_max = param->counter.max;
2537 /* PORT sends SETUP message */
2539 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);
2540 if (e_state!=EPOINT_STATE_IDLE) {
2541 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2544 port_setup(portlist, message_type, param);
2547 /* PORT sends INFORMATION message */
2548 case MESSAGE_INFORMATION: /* additional digits received */
2549 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);
2550 port_information(portlist, message_type, param);
2553 /* PORT sends FACILITY message */
2554 case MESSAGE_FACILITY:
2555 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2556 port_facility(portlist, message_type, param);
2560 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming 3PTY facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2561 port_3pty(portlist, message_type, param);
2564 case MESSAGE_TRANSFER:
2565 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming TRANSFER request (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2566 port_transfer(portlist, message_type, param);
2569 /* PORT sends DTMF message */
2570 case MESSAGE_DTMF: /* dtmf digits received */
2571 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);
2572 port_dtmf(portlist, message_type, param);
2575 /* PORT sends CRYPT message */
2576 case MESSAGE_CRYPT: /* crypt response received */
2577 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2578 port_crypt(portlist, message_type, param);
2581 /* PORT sends MORE message */
2582 case MESSAGE_OVERLAP:
2583 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);
2584 if (e_state != EPOINT_STATE_OUT_SETUP) {
2585 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);
2588 port_overlap(portlist, message_type, param);
2591 /* PORT sends PROCEEDING message */
2592 case MESSAGE_PROCEEDING: /* port is proceeding */
2593 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);
2594 if (e_state!=EPOINT_STATE_OUT_SETUP
2595 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2596 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);
2599 port_proceeding(portlist, message_type, param);
2602 /* PORT sends ALERTING message */
2603 case MESSAGE_ALERTING:
2604 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);
2605 if (e_state!=EPOINT_STATE_OUT_SETUP
2606 && e_state!=EPOINT_STATE_OUT_OVERLAP
2607 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2608 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);
2611 port_alerting(portlist, message_type, param);
2614 /* PORT sends CONNECT message */
2615 case MESSAGE_CONNECT:
2616 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);
2617 if (e_state!=EPOINT_STATE_OUT_SETUP
2618 && e_state!=EPOINT_STATE_OUT_OVERLAP
2619 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2620 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2621 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2624 port_connect(portlist, message_type, param);
2627 /* PORT sends DISCONNECT message */
2628 case MESSAGE_DISCONNECT: /* port is disconnected */
2629 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);
2630 port_disconnect_release(portlist, message_type, param);
2633 /* PORT sends a RELEASE message */
2634 case MESSAGE_RELEASE: /* port releases */
2635 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);
2636 /* portlist is release at port_disconnect_release, thanx Paul */
2637 port_disconnect_release(portlist, message_type, param);
2640 /* PORT sends a TIMEOUT message */
2641 case MESSAGE_TIMEOUT:
2642 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);
2643 port_timeout(portlist, message_type, param);
2644 break; /* release */
2646 /* PORT sends a NOTIFY message */
2647 case MESSAGE_NOTIFY:
2648 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);
2649 port_notify(portlist, message_type, param);
2652 /* PORT sends a PROGRESS message */
2653 case MESSAGE_PROGRESS:
2654 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);
2655 port_progress(portlist, message_type, param);
2658 /* PORT sends a SUSPEND message */
2659 case MESSAGE_SUSPEND:
2660 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);
2661 port_suspend(portlist, message_type, param);
2662 break; /* suspend */
2664 /* PORT sends a RESUME message */
2665 case MESSAGE_RESUME:
2666 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);
2667 port_resume(portlist, message_type, param);
2671 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2672 /* port assigns bchannel */
2673 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2674 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);
2675 /* only one port is expected to be connected to bchannel */
2676 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2677 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2681 /* PORT requests DTMF */
2682 case MESSAGE_ENABLEKEYPAD:
2683 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);
2684 port_enablekeypad(portlist, message_type, param);
2687 case MESSAGE_DISABLE_DEJITTER:
2688 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);
2689 port_disable_dejitter(portlist, message_type, param);
2692 case MESSAGE_UPDATEBRIDGE:
2693 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming updatebridge message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2694 port_updatebridge(portlist, message_type, param);
2698 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming vootp message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2699 port_vootp(portlist, message_type, param);
2702 /* PORT indivated Data-Over-Voice */
2703 case MESSAGE_DOV_INDICATION:
2704 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);
2705 port_dov_indication(portlist, message_type, param);
2709 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);
2712 /* Note: this endpoint may be destroyed, so we MUST return */
2716 /* messages from join
2718 /* join MESSAGE_CRYPT */
2719 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2722 switch(param->crypt.type) {
2723 /* message from remote port to "crypt manager" */
2724 case CU_ACTK_REQ: /* activate key-exchange */
2725 case CU_ACTS_REQ: /* activate shared key */
2726 case CU_DACT_REQ: /* deactivate */
2727 case CU_INFO_REQ: /* request last info message */
2728 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2731 /* message from "crypt manager" to user */
2732 case CU_ACTK_CONF: /* key-echange done */
2733 case CU_ACTS_CONF: /* shared key done */
2734 case CU_DACT_CONF: /* deactivated */
2735 case CU_DACT_IND: /* deactivated */
2736 case CU_ERROR_IND: /* receive error message */
2737 case CU_INFO_IND: /* receive info message */
2738 case CU_INFO_CONF: /* receive info message */
2739 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2743 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);
2748 /* join MESSAGE_INFORMATION */
2749 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2751 struct lcr_msg *message;
2756 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2757 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2758 message_put(message);
2759 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2760 portlist = portlist->next;
2764 /* join MESSAGE_FACILITY */
2765 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2767 struct lcr_msg *message;
2769 if (!e_ext.facility && e_ext.number[0]) {
2774 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2775 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2776 message_put(message);
2777 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2778 portlist = portlist->next;
2782 /* join MESSAGE_MORE */
2783 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2785 struct lcr_msg *message;
2787 new_state(EPOINT_STATE_IN_OVERLAP);
2790 if (e_join_pattern && e_ext.own_setup) {
2791 /* disconnect audio */
2792 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2793 message->param.audiopath = 0;
2794 message_put(message);
2796 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2797 if (e_dialinginfo.id[0])
2798 set_tone(portlist, "dialing");
2800 set_tone(portlist, "dialtone");
2803 if (e_dialinginfo.id[0]) {
2804 set_tone(portlist, "dialing");
2806 if (e_ext.number[0])
2807 set_tone(portlist, "dialpbx");
2809 set_tone(portlist, "dialtone");
2813 /* join MESSAGE_PROCEEDING */
2814 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2816 struct lcr_msg *message;
2818 new_state(EPOINT_STATE_IN_PROCEEDING);
2820 /* own proceeding tone */
2821 if (e_join_pattern) {
2822 /* connect / disconnect audio */
2823 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2824 if (e_ext.own_proceeding)
2825 message->param.audiopath = 0;
2827 message->param.audiopath = 1;
2828 message_put(message);
2830 // UCPY(e_join_tone, "proceeding");
2832 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2833 message_put(message);
2834 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2836 set_tone(portlist, "proceeding");
2839 /* join MESSAGE_ALERTING */
2840 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2842 struct lcr_msg *message;
2844 new_state(EPOINT_STATE_IN_ALERTING);
2846 /* own alerting tone */
2847 if (e_join_pattern) {
2848 /* connect / disconnect audio */
2849 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2850 if (e_ext.own_alerting)
2851 message->param.audiopath = 0;
2853 message->param.audiopath = 1;
2854 message_put(message);
2857 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2858 message_put(message);
2859 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2861 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2862 set_tone(portlist, "ringing");
2865 if (e_ext.number[0])
2866 set_tone(portlist, "ringpbx");
2868 set_tone(portlist, "ringing");
2870 if (e_ext.number[0])
2871 e_dtmf = 1; /* allow dtmf */
2874 /* join MESSAGE_CONNECT */
2875 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2877 struct lcr_msg *message;
2880 new_state(EPOINT_STATE_CONNECT);
2881 // UCPY(e_join_tone, "");
2883 if (e_ext.number[0])
2884 e_dtmf = 1; /* allow dtmf */
2887 unsched_timer(&e_powerdial_timeout);
2888 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2890 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2891 memcpy(&message->param, param, sizeof(union parameter));
2893 /* screen clip if prefix is required */
2894 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2895 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2896 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2897 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2900 /* use internal caller id */
2901 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2902 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2903 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2906 /* handle restricted caller ids */
2907 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);
2908 /* display callerid if desired for extension */
2909 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));
2911 /* use conp, if enabld */
2912 // if (!e_ext.centrex)
2913 // message->param.connectinfo.name[0] = '\0';
2916 message_put(message);
2917 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2919 set_tone(portlist, NULL);
2921 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2922 message->param.audiopath = 1;
2923 message_put(message);
2927 /* if the remote answered, we listen to DOV message */
2928 if (e_ext.dov_log[0]) {
2929 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_LISTEN);
2930 message->param.dov.type = e_ext.dov_type;
2931 message_put(message);
2935 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2936 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2939 struct lcr_msg *message;
2940 struct port_list *portlist = NULL;
2944 /* be sure that we are active */
2946 e_tx_state = NOTIFY_STATE_ACTIVE;
2948 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2949 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2950 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2952 /* set time for power dialing */
2953 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2956 /* set redial tone */
2957 if (ea_endpoint->ep_portlist) {
2960 set_tone(ea_endpoint->ep_portlist, "redial");
2961 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);
2962 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2963 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2964 new_state(EPOINT_STATE_IN_PROCEEDING);
2965 if (ea_endpoint->ep_portlist) {
2966 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2967 message_put(message);
2968 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2970 /* caused the error, that the first knock sound was not there */
2971 /* set_tone(portlist, "proceeding"); */
2973 /* send display of powerdialing */
2974 if (e_ext.display_dialing) {
2975 portlist = ea_endpoint->ep_portlist;
2977 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2979 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2981 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2982 message_put(message);
2983 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2984 portlist = portlist->next;
2994 if ((e_state!=EPOINT_STATE_CONNECT
2995 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2996 && e_state!=EPOINT_STATE_IN_OVERLAP
2997 && e_state!=EPOINT_STATE_IN_PROCEEDING
2998 && e_state!=EPOINT_STATE_IN_ALERTING)
2999 || !ea_endpoint->ep_portlist) { /* or no port */
3000 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3001 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3002 return; /* must exit here */
3005 if (!e_join_cause) {
3006 e_join_cause = param->disconnectinfo.cause;
3007 e_join_location = param->disconnectinfo.location;
3010 /* on release we need the audio again! */
3011 if (message_type == MESSAGE_RELEASE) {
3013 ea_endpoint->ep_join_id = 0;
3015 /* disconnect and select tone */
3016 new_state(EPOINT_STATE_OUT_DISCONNECT);
3017 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3018 /* if own_cause, we must release the join */
3019 if (e_ext.own_cause /* own cause */
3020 || !e_join_pattern) { /* no patterns */
3021 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);
3022 if (message_type != MESSAGE_RELEASE)
3023 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3025 } else { /* else we enable audio */
3026 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3027 message->param.audiopath = 1;
3028 message_put(message);
3030 /* send disconnect message */
3031 SCPY(e_tone, cause);
3032 portlist = ea_endpoint->ep_portlist;
3034 set_tone(portlist, cause);
3035 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "", ¶m->disconnectinfo.transfer);
3036 portlist = portlist->next;
3040 /* join MESSAGE_SETUP */
3041 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3043 struct lcr_msg *message;
3044 // struct interface *interface;
3046 /* if we already in setup state, we just update the dialing with new digits */
3047 if (e_state == EPOINT_STATE_OUT_SETUP
3048 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3049 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3050 /* if digits changed, what we have already dialed */
3051 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3052 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);
3053 /* release all ports */
3054 while((portlist = ea_endpoint->ep_portlist)) {
3055 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3056 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3057 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3058 message_put(message);
3059 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3060 ea_endpoint->free_portlist(portlist);
3063 /* disconnect audio */
3064 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3065 message->param.audiopath = 0;
3066 message_put(message);
3068 /* get dialing info */
3069 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3070 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3071 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3072 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3073 new_state(EPOINT_STATE_OUT_OVERLAP);
3076 schedule_timer(&e_redial_timeout, 1, 0);
3079 /* if we have a pending redial, so we just adjust the dialing number */
3080 if (e_redial_timeout.active) {
3081 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);
3082 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3085 if (!ea_endpoint->ep_portlist) {
3086 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3088 if (ea_endpoint->ep_portlist->next) {
3089 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3091 if (e_state == EPOINT_STATE_OUT_SETUP) {
3093 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);
3094 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3097 /* get what we have not dialed yet */
3098 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));
3099 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3100 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3101 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3102 message_put(message);
3103 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3105 /* always store what we have dialed or queued */
3106 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3110 if (e_state != EPOINT_STATE_IDLE) {
3111 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3114 /* if an internal extension is dialed, copy that number */
3115 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3116 SCPY(e_ext.number, param->setup.dialinginfo.id);
3117 /* if an internal extension is dialed, get extension's info about caller */
3118 if (e_ext.number[0]) {
3119 if (!read_extension(&e_ext, e_ext.number)) {
3120 e_ext.number[0] = '\0';
3121 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3125 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3126 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3127 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3128 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3129 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3131 /* process (voice over) data calls */
3132 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3133 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3134 memset(&e_capainfo, 0, sizeof(e_capainfo));
3135 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3136 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3137 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3140 new_state(EPOINT_STATE_OUT_SETUP);
3141 /* call special setup routine */
3145 /* join MESSAGE_mISDNSIGNAL */
3146 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3148 struct lcr_msg *message;
3151 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3152 memcpy(&message->param, param, sizeof(union parameter));
3153 message_put(message);
3154 portlist = portlist->next;
3158 /* join MESSAGE_BRIDE */
3159 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3161 struct lcr_msg *message;
3164 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3165 memcpy(&message->param, param, sizeof(union parameter));
3166 message_put(message);
3167 portlist = portlist->next;
3171 /* join MESSAGE_NOTIFY */
3172 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3174 struct lcr_msg *message;
3177 if (param->notifyinfo.notify) {
3178 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3179 // /* if notification was generated locally, we turn hold music on/off */
3180 // if (param->notifyinfo.local)
3181 // 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)
3185 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3186 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3188 set_tone(portlist, "");
3189 portlist = portlist->next;
3192 portlist = ea_endpoint->ep_portlist;
3197 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3199 set_tone(portlist, "hold");
3200 portlist = portlist->next;
3202 portlist = ea_endpoint->ep_portlist;
3207 /* save new state */
3208 e_tx_state = new_state;
3211 /* notify port(s) about it */
3213 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3214 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3215 /* handle restricted caller ids */
3216 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3217 /* display callerid if desired for extension */
3218 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));
3219 message_put(message);
3220 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3221 portlist = portlist->next;
3225 /* join MESSAGE_DTMF */
3226 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3228 struct lcr_msg *message;
3231 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3232 memcpy(&message->param, param, sizeof(union parameter));
3233 message_put(message);
3234 portlist = portlist->next;
3238 /* join MESSAGE_DISABLE_DEJITTER */
3239 void EndpointAppPBX::join_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
3241 struct lcr_msg *message;
3244 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISABLE_DEJITTER);
3245 memcpy(&message->param, param, sizeof(union parameter));
3246 message_put(message);
3247 portlist = portlist->next;
3251 /* join MESSAGE_DOV_INDICATION */
3252 void EndpointAppPBX::join_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
3254 dov_msg_write(param, 0);
3257 /* join MESSAGE_DOV_REQUEST */
3258 void EndpointAppPBX::join_dov_request(struct port_list *portlist, int message_type, union parameter *param)
3260 struct lcr_msg *message;
3262 /* don't send DOV from estension to extension */
3263 if (e_ext.number[0])
3267 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_REQUEST);
3268 memcpy(&message->param, param, sizeof(union parameter));
3269 message_put(message);
3270 logmessage(message_type, param, portlist->port_id, DIRECTION_OUT);
3271 portlist = portlist->next;
3275 /* join MESSAGE_DOV_LISTEN */
3276 void EndpointAppPBX::join_dov_listen(struct port_list *portlist, int message_type, union parameter *param)
3278 struct lcr_msg *message;
3281 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_LISTEN);
3282 memcpy(&message->param, param, sizeof(union parameter));
3283 message_put(message);
3284 portlist = portlist->next;
3288 /* JOIN sends messages to the endpoint
3290 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3292 struct port_list *portlist;
3293 struct lcr_msg *message;
3296 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3300 portlist = ea_endpoint->ep_portlist;
3302 // 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);
3303 switch(message_type) {
3304 /* JOIN SENDS TONE message */
3306 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);
3307 set_tone(portlist, param->tone.name);
3310 /* JOIN SENDS CRYPT message */
3312 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);
3313 join_crypt(portlist, message_type, param);
3316 /* JOIN sends INFORMATION message */
3317 case MESSAGE_INFORMATION:
3318 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);
3319 join_information(portlist, message_type, param);
3322 /* JOIN sends FACILITY message */
3323 case MESSAGE_FACILITY:
3324 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);
3325 join_facility(portlist, message_type, param);
3328 /* JOIN sends OVERLAP message */
3329 case MESSAGE_OVERLAP:
3330 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);
3331 if (e_state!=EPOINT_STATE_IN_SETUP
3332 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3333 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3336 join_overlap(portlist, message_type, param);
3339 /* JOIN sends PROCEEDING message */
3340 case MESSAGE_PROCEEDING:
3341 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);
3342 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3343 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3346 join_proceeding(portlist, message_type, param);
3349 /* JOIN sends ALERTING message */
3350 case MESSAGE_ALERTING:
3351 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);
3352 if (e_state!=EPOINT_STATE_IN_OVERLAP
3353 && e_state!=EPOINT_STATE_IN_PROCEEDING
3354 && e_state!=EPOINT_STATE_IN_ALERTING /* second alerting */
3355 && e_state!=EPOINT_STATE_CONNECT) { /* alerting after transfer */
3356 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3359 join_alerting(portlist, message_type, param);
3362 /* JOIN sends CONNECT message */
3363 case MESSAGE_CONNECT:
3364 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);
3365 if (e_state!=EPOINT_STATE_IN_OVERLAP
3366 && e_state!=EPOINT_STATE_IN_PROCEEDING
3367 && e_state!=EPOINT_STATE_IN_ALERTING) {
3368 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3371 join_connect(portlist, message_type, param);
3374 /* JOIN sends DISCONNECT/RELEASE message */
3375 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3376 case MESSAGE_RELEASE: /* JOIN releases */
3377 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);
3378 join_disconnect_release(message_type, param);
3381 /* JOIN sends SETUP message */
3383 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);
3384 join_setup(portlist, message_type, param);
3387 /* JOIN sends special mISDNSIGNAL message */
3388 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3389 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);
3390 join_mISDNsignal(portlist, message_type, param);
3393 /* JOIN sends bridge message */
3394 case MESSAGE_BRIDGE: /* bride message to port */
3395 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);
3396 join_bridge(portlist, message_type, param);
3399 /* JOIN has pattern available */
3400 case MESSAGE_PATTERN: /* indicating pattern available */
3401 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);
3402 if (!e_join_pattern) {
3403 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3407 set_tone(portlist, NULL);
3408 portlist = portlist->next;
3410 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3411 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3412 message->param.audiopath = 1;
3413 message_put(message);
3417 /* JOIN has no pattern available */
3418 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3419 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);
3420 if (e_join_pattern) {
3421 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3423 /* disconnect our audio tx and rx */
3424 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3425 message->param.audiopath = 0;
3426 message_put(message);
3431 /* JOIN (dunno at the moment) */
3432 case MESSAGE_REMOTE_AUDIO:
3433 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);
3434 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3435 message->param.audiopath = param->channel;
3436 message_put(message);
3440 /* JOIN sends a notify message */
3441 case MESSAGE_NOTIFY:
3442 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);
3443 join_notify(portlist, message_type, param);
3446 /* JOIN wants keypad / dtmf */
3447 case MESSAGE_ENABLEKEYPAD:
3448 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);
3451 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3455 /* JOIN sends a DTMF message */
3457 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);
3458 join_dtmf(portlist, message_type, param);
3461 /* JOIN sends a DISABLE_DEJITTER message */
3462 case MESSAGE_DISABLE_DEJITTER:
3463 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);
3464 join_disable_dejitter(portlist, message_type, param);
3467 /* JOIN sends a Data-Over-Voice message indication */
3468 case MESSAGE_DOV_INDICATION:
3469 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);
3470 join_dov_indication(portlist, message_type, param);
3473 /* JOIN sends a Data-Over-Voice message request */
3474 case MESSAGE_DOV_REQUEST:
3475 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);
3476 join_dov_request(portlist, message_type, param);
3479 /* JOIN sends a Data-Over-Voice listen order */
3480 case MESSAGE_DOV_LISTEN:
3481 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);
3482 join_dov_listen(portlist, message_type, param);
3486 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);
3491 /* pick_join will connect the first incoming call found. the endpoint
3492 * will receivce a MESSAGE_CONNECT.
3494 int match_list(char *list, char *item)
3496 char *end, *next = NULL;
3498 /* no list make matching */
3503 /* eliminate white spaces */
3504 while (*list > '\0' && *list <= ' ')
3510 /* if end of list is reached, we return */
3511 if (list[0] == '\0')
3513 /* if we have more than one entry (left) */
3514 if ((end = strchr(list, ',')))
3517 next = end = strchr(list, '\0');
3518 while (*(end-1) <= ' ')
3520 /* if string part matches item */
3521 if (!strncmp(list, item, end-list))
3527 void EndpointAppPBX::pick_join(char *extensions)
3529 struct lcr_msg *message;
3530 struct port_list *portlist;
3532 class EndpointAppPBX *eapp, *found;
3534 class JoinPBX *joinpbx;
3535 struct join_relation *relation;
3537 /* find an endpoint that is ringing internally or vbox with higher priority */
3539 eapp = apppbx_first;
3541 if (eapp!=this && ea_endpoint->ep_portlist) {
3542 portlist = eapp->ea_endpoint->ep_portlist;
3544 if ((port = find_port_id(portlist->port_id))) {
3545 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3546 if (match_list(extensions, eapp->e_ext.number)) {
3551 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3552 && port->p_state==PORT_STATE_OUT_ALERTING)
3553 if (match_list(extensions, eapp->e_ext.number)) {
3557 portlist = portlist->next;
3565 /* if no endpoint found */
3567 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);
3569 set_tone(ea_endpoint->ep_portlist, "cause_10");
3570 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL);
3571 new_state(EPOINT_STATE_OUT_DISCONNECT);
3576 if (ea_endpoint->ep_join_id) {
3577 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3580 if (!eapp->ea_endpoint->ep_join_id) {
3581 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3584 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3586 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3589 if (join->j_type != JOIN_TYPE_PBX) {
3590 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3593 joinpbx = (class JoinPBX *)join;
3594 relation = joinpbx->j_relation;
3596 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3599 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3600 relation = relation->next;
3602 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3607 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3609 if (options.deb & DEBUG_EPOINT) {
3610 class Join *debug_c = join_first;
3611 class Endpoint *debug_e = epoint_first;
3612 class Port *debug_p = port_first;
3614 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3616 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3618 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3619 debug_c = debug_c->next;
3621 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3623 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3624 debug_e = debug_e->next;
3626 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3628 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3629 debug_p = debug_p->next;
3634 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3635 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3636 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3638 /* connnecting our endpoint */
3639 new_state(EPOINT_STATE_CONNECT);
3640 if (e_ext.number[0])
3642 set_tone(ea_endpoint->ep_portlist, NULL);
3644 /* now we send a release to the ringing endpoint */
3645 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3646 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3647 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3648 message_put(message);
3650 /* we send a connect to the join with our caller id */
3651 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3652 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3653 message->param.connectinfo.present = e_callerinfo.present;
3654 message->param.connectinfo.screen = e_callerinfo.screen;
3655 message->param.connectinfo.itype = e_callerinfo.itype;
3656 message->param.connectinfo.ntype = e_callerinfo.ntype;
3657 message_put(message);
3659 /* we send a connect to our port with the remote callerid */
3660 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3661 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3662 message->param.connectinfo.present = eapp->e_callerinfo.present;
3663 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3664 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3665 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3666 /* handle restricted caller ids */
3667 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);
3668 /* display callerid if desired for extension */
3669 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));
3670 message_put(message);
3672 /* we send a connect to the audio path (not for vbox) */
3673 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3674 message->param.audiopath = 1;
3675 message_put(message);
3677 /* beeing paranoid, we make call update */
3678 trigger_work(&joinpbx->j_updatebridge);
3680 if (options.deb & DEBUG_EPOINT) {
3681 class Join *debug_c = join_first;
3682 class Endpoint *debug_e = epoint_first;
3683 class Port *debug_p = port_first;
3685 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3687 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3689 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3690 debug_c = debug_c->next;
3692 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3694 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3695 debug_e = debug_e->next;
3697 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3699 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3700 debug_p = debug_p->next;
3706 /* join calls (look for a join that is on hold (same isdn/gsm interface/terminal))
3708 int EndpointAppPBX::join_join_dss1(int invoke_id)
3710 struct lcr_msg *message;
3711 struct join_relation *add_relation, *remove_relation;
3712 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3713 class Join *our_join, *other_join, *add_join, *remove_join;
3714 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3715 class EndpointAppPBX *other_eapp, *remove_eapp_hold, *remove_eapp_active;
3716 class Port *our_port, *other_port;
3718 class Pdss1 *our_pdss1 = NULL, *other_pdss1;
3721 class Pgsm_bs *our_gsm_bs = NULL, *other_gsm_bs;
3723 class Endpoint *temp_epoint;
3725 /* are we a candidate to join a join? */
3726 our_join = find_join_id(ea_endpoint->ep_join_id);
3728 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3731 if (our_join->j_type != JOIN_TYPE_PBX) {
3732 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3735 our_joinpbx = (class JoinPBX *)our_join;
3736 if (!ea_endpoint->ep_portlist) {
3737 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3740 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3742 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3746 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1)
3747 our_pdss1 = (class Pdss1 *)our_port;
3750 if ((our_port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS)
3751 our_gsm_bs = (class Pgsm_bs *)our_port;
3754 /* find an endpoint that has the same mISDNport/ces that we are on */
3755 other_eapp = apppbx_first;
3757 if (other_eapp == this) {
3758 other_eapp = other_eapp->next;
3761 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);
3762 if (other_eapp->ea_endpoint->ep_portlist /* has port */
3763 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3764 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3765 if (other_port) { /* port still exists */
3768 && (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3769 || other_port->p_type==PORT_TYPE_DSS1_NT_IN)) { /* port is isdn nt-mode */
3770 other_pdss1 = (class Pdss1 *)other_port;
3771 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_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
3772 if (1 //other_pdss1->p_hold /* port is on hold */
3773 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3774 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3780 && (other_port->p_type==PORT_TYPE_GSM_BS_OUT
3781 || other_port->p_type==PORT_TYPE_GSM_BS_IN)) { /* port is GSM bs-mode */
3782 other_gsm_bs = (class Pgsm_bs *)other_port;
3783 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type GSM! comparing our imsi with other imsi=%s\n", ea_endpoint->ep_serial, our_gsm_bs->p_g_imsi, other_gsm_bs->p_g_imsi);
3784 if (!strcmp(other_gsm_bs->p_g_imsi, our_gsm_bs->p_g_imsi)) /* same tei+sapi */
3789 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3792 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3795 other_eapp = other_eapp->next;
3798 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3801 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3803 /* if we have the same join */
3804 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3805 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3808 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3810 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3813 if (other_join->j_type != JOIN_TYPE_PBX) {
3814 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3817 other_joinpbx = (class JoinPBX *)other_join;
3818 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3819 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3823 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3824 if (our_port->p_hold && !other_port->p_hold) {
3825 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);
3826 remove_eapp_hold = this;
3827 remove_eapp_active = other_eapp;
3828 remove_join = our_join;
3829 remove_joinpbx = our_joinpbx;
3830 add_join = other_join;
3831 add_joinpbx = other_joinpbx;
3833 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);
3834 remove_eapp_hold = other_eapp;
3835 remove_eapp_active = this;
3836 remove_join = other_join;
3837 remove_joinpbx = other_joinpbx;
3838 add_join = our_join;
3839 add_joinpbx = our_joinpbx;
3842 /* remove relation to endpoint for join on hold */
3843 remove_relation = remove_joinpbx->j_relation;
3844 remove_relation_pointer = &remove_joinpbx->j_relation;
3845 while(remove_relation) {
3846 if (remove_relation->epoint_id == remove_eapp_hold->ea_endpoint->ep_serial) {
3847 /* detach endpoint on hold */
3848 *remove_relation_pointer = remove_relation->next;
3849 FREE(remove_relation, sizeof(struct join_relation));
3851 remove_relation = *remove_relation_pointer;
3852 remove_eapp_hold->ea_endpoint->ep_join_id = 0;
3856 /* change join/hold pointer of endpoint to the new join */
3857 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3859 if (temp_epoint->ep_join_id == remove_join->j_serial)
3860 temp_epoint->ep_join_id = add_join->j_serial;
3863 remove_relation_pointer = &remove_relation->next;
3864 remove_relation = remove_relation->next;
3866 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint (hold) removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3868 if (invoke_id >= 0) {
3869 /* remove relation to endpoint for active join */
3870 remove_relation = add_joinpbx->j_relation;
3871 remove_relation_pointer = &add_joinpbx->j_relation;
3872 while(remove_relation) {
3873 if (remove_relation->epoint_id == remove_eapp_active->ea_endpoint->ep_serial) {
3874 /* detach active endpoint */
3875 *remove_relation_pointer = remove_relation->next;
3876 FREE(remove_relation, sizeof(struct join_relation));
3878 remove_relation = *remove_relation_pointer;
3879 remove_eapp_active->ea_endpoint->ep_join_id = 0;
3883 remove_relation_pointer = &remove_relation->next;
3884 remove_relation = remove_relation->next;
3886 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint (active) removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3888 /* if active endpoint is in alerting state, send alerting message to join */
3889 if (remove_eapp_active->e_state == EPOINT_STATE_IN_ALERTING) {
3890 if (add_joinpbx->j_relation && !add_joinpbx->j_relation->next) {
3891 /* if channel state indicateds "audio" (1), we tell the other endpoint that patterns are available */
3892 if (add_joinpbx->j_relation->channel_state) {
3893 message = message_create(add_joinpbx->j_relation->epoint_id, add_join->j_serial, EPOINT_TO_JOIN, MESSAGE_PATTERN);
3894 message_put(message);
3896 message = message_create(add_joinpbx->j_relation->epoint_id, add_join->j_serial, EPOINT_TO_JOIN, MESSAGE_ALERTING);
3897 message_put(message);
3902 /* join call relations: we add the members of the join on hold to the active join */
3903 add_relation = add_joinpbx->j_relation;
3904 add_relation_pointer = &add_joinpbx->j_relation;
3905 while(add_relation) {
3906 add_relation_pointer = &add_relation->next;
3907 add_relation = add_relation->next;
3909 *add_relation_pointer = remove_joinpbx->j_relation;
3910 remove_joinpbx->j_relation = NULL;
3911 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3913 /* release endpoint on hold */
3914 message = message_create(remove_joinpbx->j_serial, remove_eapp_hold->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3915 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3916 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3917 if (invoke_id >= 0) {
3918 /* send the result with disconnect message to the invoking endpoint */
3919 if (remove_eapp_hold->ea_endpoint->ep_serial == ea_endpoint->ep_serial) {
3920 message->param.disconnectinfo.transfer.result = 1;
3921 message->param.disconnectinfo.transfer.invoke_id = invoke_id;
3924 message_put(message);
3926 if (invoke_id >= 0) {
3927 /* release active endpoint */
3928 message = message_create(add_joinpbx->j_serial, remove_eapp_active->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3929 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3930 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3931 /* send the result with disconnect message to the invoking endpoint */
3932 if (remove_eapp_active->ea_endpoint->ep_serial == ea_endpoint->ep_serial) {
3933 message->param.disconnectinfo.transfer.result = 1;
3934 message->param.disconnectinfo.transfer.invoke_id = invoke_id;
3936 message_put(message);
3939 /* if we are not a partyline, we get partyline state from other join */
3940 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3942 /* remove empty join */
3944 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3946 /* mixer must update */
3947 trigger_work(&add_joinpbx->j_updatebridge);
3949 /* we send a retrieve to that endpoint */
3950 // mixer will update the hold-state of the join and send it to the endpoints is changes
3955 /* join calls (look for a join that is on hold (same fxs interface/terminal))
3957 int EndpointAppPBX::join_join_fxs(void)
3960 struct lcr_msg *message;
3961 struct join_relation *add_relation, *remove_relation;
3962 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3963 class Join *our_join, *other_join, *add_join, *remove_join;
3964 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3965 class EndpointAppPBX *other_eapp, *remove_eapp;
3966 class Port *our_port, *other_port;
3967 class Pfxs *our_fxs, *other_fxs;
3968 class Endpoint *temp_epoint;
3970 /* are we a candidate to join a join? */
3971 our_join = find_join_id(ea_endpoint->ep_join_id);
3973 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3976 if (our_join->j_type != JOIN_TYPE_PBX) {
3977 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3980 our_joinpbx = (class JoinPBX *)our_join;
3981 if (!ea_endpoint->ep_portlist) {
3982 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3985 if (!e_ext.number[0]) {
3986 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3989 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3991 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3994 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
3995 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not fxs.\n", ea_endpoint->ep_serial);
3998 our_fxs = (class Pfxs *)our_port;
4000 /* find an endpoint that has the same mISDNport that we are on */
4001 other_eapp = apppbx_first;
4003 if (other_eapp == this) {
4004 other_eapp = other_eapp->next;
4007 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);
4008 if (other_eapp->e_ext.number[0] /* has terminal */
4009 && other_eapp->ea_endpoint->ep_portlist /* has port */
4010 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4011 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4012 if (other_port) { /* port still exists */
4013 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4014 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is FXS */
4015 other_fxs = (class Pfxs *)other_port;
4016 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_hold)?"YES":"NO", other_fxs->p_state);
4017 if (1 //other_fxs->p_hold /* port is on hold */
4018 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
4021 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4024 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4027 other_eapp = other_eapp->next;
4030 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4033 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4035 /* if we have the same join */
4036 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4037 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4040 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4042 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4045 if (other_join->j_type != JOIN_TYPE_PBX) {
4046 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4049 other_joinpbx = (class JoinPBX *)other_join;
4050 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4051 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4055 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
4056 if (our_port->p_hold && !other_port->p_hold) {
4057 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);
4059 remove_join = our_join;
4060 remove_joinpbx = our_joinpbx;
4061 add_join = other_join;
4062 add_joinpbx = other_joinpbx;
4064 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);
4065 remove_eapp = other_eapp;
4066 remove_join = other_join;
4067 remove_joinpbx = other_joinpbx;
4068 add_join = our_join;
4069 add_joinpbx = our_joinpbx;
4072 /* remove relation to endpoint for join on hold */
4073 remove_relation = remove_joinpbx->j_relation;
4074 remove_relation_pointer = &remove_joinpbx->j_relation;
4075 while(remove_relation) {
4076 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
4077 /* detach other endpoint */
4078 *remove_relation_pointer = remove_relation->next;
4079 FREE(remove_relation, sizeof(struct join_relation));
4081 remove_relation = *remove_relation_pointer;
4082 remove_eapp->ea_endpoint->ep_join_id = 0;
4086 /* change join/hold pointer of endpoint to the new join */
4087 temp_epoint = find_epoint_id(remove_relation->epoint_id);
4089 if (temp_epoint->ep_join_id == remove_join->j_serial)
4090 temp_epoint->ep_join_id = add_join->j_serial;
4093 remove_relation_pointer = &remove_relation->next;
4094 remove_relation = remove_relation->next;
4096 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
4098 /* join call relations */
4099 add_relation = add_joinpbx->j_relation;
4100 add_relation_pointer = &add_joinpbx->j_relation;
4101 while(add_relation) {
4102 add_relation_pointer = &add_relation->next;
4103 add_relation = add_relation->next;
4105 *add_relation_pointer = remove_joinpbx->j_relation;
4106 remove_joinpbx->j_relation = NULL;
4107 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
4109 /* release endpoint */
4110 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
4111 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
4112 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
4113 message_put(message);
4115 /* if we are not a partyline, we get partyline state from other join */
4116 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
4118 /* remove empty join */
4120 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
4122 /* mixer must update */
4123 trigger_work(&add_joinpbx->j_updatebridge);
4125 /* we send a retrieve to that endpoint */
4126 // mixer will update the hold-state of the join and send it to the endpoints is changes
4130 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4136 /* do audio bridge of endpoints on same isdn/gsm terminal */
4137 int EndpointAppPBX::join_3pty_dss1(void)
4139 class Join *our_join, *other_join;
4140 class JoinPBX *our_joinpbx, *other_joinpbx;
4141 class EndpointAppPBX *other_eapp;
4142 class Port *our_port, *other_port;
4144 class Pdss1 *our_pdss1 = NULL, *other_pdss1;
4147 class Pgsm_bs *our_gsm_bs = NULL, *other_gsm_bs;
4150 /* are we a candidate to join a join? */
4151 our_join = find_join_id(ea_endpoint->ep_join_id);
4153 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4156 if (our_join->j_type != JOIN_TYPE_PBX) {
4157 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4160 our_joinpbx = (class JoinPBX *)our_join;
4161 if (!ea_endpoint->ep_portlist) {
4162 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4165 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4167 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4171 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_DSS1)
4172 our_pdss1 = (class Pdss1 *)our_port;
4175 if ((our_port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS)
4176 our_gsm_bs = (class Pgsm_bs *)our_port;
4179 /* find an endpoint that has the same mISDNport/ces that we are on */
4180 other_eapp = apppbx_first;
4182 if (other_eapp == this) {
4183 other_eapp = other_eapp->next;
4186 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);
4187 if (other_eapp->ea_endpoint->ep_portlist /* has port */
4188 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4189 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4190 if (other_port) { /* port still exists */
4193 && (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
4194 || other_port->p_type==PORT_TYPE_DSS1_NT_IN)) { /* port is isdn nt-mode */
4195 other_pdss1 = (class Pdss1 *)other_port;
4196 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_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
4197 if (1 //other_pdss1->p_hold /* port is on hold */
4198 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
4199 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
4205 && (other_port->p_type==PORT_TYPE_GSM_BS_OUT
4206 || other_port->p_type==PORT_TYPE_GSM_BS_IN)) { /* port is GSM bs-mode */
4207 other_gsm_bs = (class Pgsm_bs *)other_port;
4208 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type GSM! comparing our imsi with other imsi=%s\n", ea_endpoint->ep_serial, our_gsm_bs->p_g_imsi, other_gsm_bs->p_g_imsi);
4209 if (!strcmp(other_gsm_bs->p_g_imsi, our_gsm_bs->p_g_imsi)) /* same tei+sapi */
4214 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4217 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4220 other_eapp = other_eapp->next;
4223 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same terminal.\n", ea_endpoint->ep_serial);
4226 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4228 /* if we have the same join */
4229 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4230 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4233 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4235 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4238 if (other_join->j_type != JOIN_TYPE_PBX) {
4239 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4242 other_joinpbx = (class JoinPBX *)other_join;
4243 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4244 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4248 if (our_joinpbx->j_3pty) {
4249 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4252 if (other_joinpbx->j_3pty) {
4253 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4257 /* set 3PTY bridge */
4258 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4259 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4261 /* mixer must update */
4262 trigger_work(&our_joinpbx->j_updatebridge);
4263 trigger_work(&other_joinpbx->j_updatebridge);
4265 /* we send a retrieve to that endpoint */
4266 // mixer will update the hold-state of the join and send it to the endpoints is changes
4271 /* do audio bridge of endpoints on same fxs terminal */
4272 int EndpointAppPBX::join_3pty_fxs(void)
4275 class Join *our_join, *other_join;
4276 class JoinPBX *our_joinpbx, *other_joinpbx;
4277 class EndpointAppPBX *other_eapp;
4278 class Port *our_port, *other_port;
4279 class Pfxs *our_fxs, *other_fxs;
4281 /* are we a candidate to join a join? */
4282 our_join = find_join_id(ea_endpoint->ep_join_id);
4284 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4287 if (our_join->j_type != JOIN_TYPE_PBX) {
4288 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4291 our_joinpbx = (class JoinPBX *)our_join;
4292 if (!ea_endpoint->ep_portlist) {
4293 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4296 if (!e_ext.number[0]) {
4297 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4300 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4302 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4305 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
4306 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not FXS pots.\n", ea_endpoint->ep_serial);
4309 our_fxs = (class Pfxs *)our_port;
4311 /* find an endpoint that has the same mISDNport that we are on */
4312 other_eapp = apppbx_first;
4314 if (other_eapp == this) {
4315 other_eapp = other_eapp->next;
4318 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);
4319 if (other_eapp->e_ext.number[0] /* has terminal */
4320 && other_eapp->ea_endpoint->ep_portlist /* has port */
4321 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4322 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4323 if (other_port) { /* port still exists */
4324 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4325 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is isdn nt-mode */
4326 other_fxs = (class Pfxs *)other_port;
4327 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_hold)?"YES":"NO", other_fxs->p_state);
4328 if (1 //other_fxs->p_hold /* port is on hold */
4329 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
4332 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4335 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4338 other_eapp = other_eapp->next;
4341 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4344 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4346 /* if we have the same join */
4347 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4348 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4351 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4353 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4356 if (other_join->j_type != JOIN_TYPE_PBX) {
4357 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4360 other_joinpbx = (class JoinPBX *)other_join;
4361 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4362 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4366 if (our_joinpbx->j_3pty) {
4367 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4370 if (other_joinpbx->j_3pty) {
4371 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4375 /* set 3PTY bridge */
4376 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4377 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4379 /* mixer must update */
4380 trigger_work(&our_joinpbx->j_updatebridge);
4381 trigger_work(&other_joinpbx->j_updatebridge);
4383 /* we send a retrieve to that endpoint */
4384 // mixer will update the hold-state of the join and send it to the endpoints is changes
4388 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4394 /* split audio bridge */
4395 int EndpointAppPBX::split_3pty(void)
4397 class Join *our_join, *other_join;
4398 class JoinPBX *our_joinpbx, *other_joinpbx;
4400 /* are we a candidate to join a join? */
4401 our_join = find_join_id(ea_endpoint->ep_join_id);
4403 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4406 if (our_join->j_type != JOIN_TYPE_PBX) {
4407 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4410 our_joinpbx = (class JoinPBX *)our_join;
4412 if (!our_joinpbx->j_3pty) {
4413 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
4417 other_join = find_join_id(our_joinpbx->j_3pty);
4419 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4422 if (other_join->j_type != JOIN_TYPE_PBX) {
4423 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4426 other_joinpbx = (class JoinPBX *)other_join;
4428 our_joinpbx->j_3pty = 0;
4429 other_joinpbx->j_3pty = 0;
4431 /* mixer must update */
4432 trigger_work(&our_joinpbx->j_updatebridge);
4433 trigger_work(&other_joinpbx->j_updatebridge);
4435 /* we send a retrieve to that endpoint */
4436 // mixer will update the hold-state of the join and send it to the endpoints is changes
4441 /* check if we have an external call
4442 * this is used to check for encryption ability
4444 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
4446 struct join_relation *relation;
4448 class JoinPBX *joinpbx;
4449 class Endpoint *epoint;
4451 /* some paranoia check */
4452 if (!ea_endpoint->ep_portlist) {
4453 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4454 *errstr = "No Call";
4457 if (!e_ext.number[0]) {
4458 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4459 *errstr = "No Call";
4463 /* check if we have a join with 2 parties */
4464 join = find_join_id(ea_endpoint->ep_join_id);
4466 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
4467 *errstr = "No Call";
4470 if (join->j_type != JOIN_TYPE_PBX) {
4471 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4472 *errstr = "No PBX Call";
4475 joinpbx = (class JoinPBX *)join;
4476 relation = joinpbx->j_relation;
4478 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4479 *errstr = "No Call";
4482 if (!relation->next) {
4483 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4484 *errstr = "No Call";
4487 if (relation->next->next) {
4488 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4489 *errstr = "Err: Conference";
4492 if (relation->epoint_id == ea_endpoint->ep_serial) {
4493 relation = relation->next;
4494 if (relation->epoint_id == ea_endpoint->ep_serial) {
4495 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4496 *errstr = "Software Error";
4501 /* check remote port for external call */
4502 epoint = find_epoint_id(relation->epoint_id);
4504 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4505 *errstr = "No Call";
4508 if (!epoint->ep_portlist) {
4509 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4510 *errstr = "No Call";
4513 *port = find_port_id(epoint->ep_portlist->port_id);
4515 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4516 *errstr = "No Call";
4519 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4520 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4521 *errstr = "No Ext Call";
4524 if ((*port)->p_state != PORT_STATE_CONNECT) {
4525 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4526 *errstr = "No Ext Connect";
4532 int EndpointAppPBX::vootp_on(int on)
4535 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4537 if (!e_ext.otp_ident[0]) {
4538 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4541 if(ea_endpoint->ep_portlist) {
4542 struct lcr_msg *message;
4544 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VOOTP);
4545 message->param.vootp.enable = on;
4546 SCPY(message->param.vootp.id, e_ext.otp_ident);
4547 message_put(message);
4550 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4556 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4558 const char *logtext = "unknown";
4561 switch(message_type) {
4563 trace_header("SETUP", dir);
4564 if (dir == DIRECTION_OUT)
4565 add_trace("to", NULL, "CH(%lu)", port_id);
4566 if (dir == DIRECTION_IN)
4567 add_trace("from", NULL, "CH(%lu)", port_id);
4568 if (param->setup.callerinfo.extension[0])
4569 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4570 if (param->setup.callerinfo.interface[0])
4571 add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
4572 if (param->setup.dialinginfo.interfaces[0])
4573 add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
4574 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4575 switch(param->setup.callerinfo.present) {
4576 case INFO_PRESENT_RESTRICTED:
4577 add_trace("caller id", "present", "restricted");
4579 case INFO_PRESENT_ALLOWED:
4580 add_trace("caller id", "present", "allowed");
4583 add_trace("caller id", "present", "not available");
4585 if (param->setup.callerinfo.ntype2) {
4586 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4587 switch(param->setup.callerinfo.present) {
4588 case INFO_PRESENT_RESTRICTED:
4589 add_trace("caller id2", "present", "restricted");
4591 case INFO_PRESENT_ALLOWED:
4592 add_trace("caller id2", "present", "allowed");
4595 add_trace("caller id2", "present", "not available");
4598 if (param->setup.redirinfo.id[0]) {
4599 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4600 switch(param->setup.redirinfo.present) {
4601 case INFO_PRESENT_RESTRICTED:
4602 add_trace("redir'ing", "present", "restricted");
4604 case INFO_PRESENT_ALLOWED:
4605 add_trace("redir'ing", "present", "allowed");
4608 add_trace("redir'ing", "present", "not available");
4611 if (param->setup.dialinginfo.id[0])
4612 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4613 if (param->setup.dialinginfo.keypad[0])
4614 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4615 if (param->setup.dialinginfo.display[0])
4616 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4617 if (param->setup.dialinginfo.sending_complete)
4618 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4622 case MESSAGE_OVERLAP:
4623 trace_header("SETUP ACKNOWLEDGE", dir);
4624 if (dir == DIRECTION_OUT)
4625 add_trace("to", NULL, "CH(%lu)", port_id);
4626 if (dir == DIRECTION_IN)
4627 add_trace("from", NULL, "CH(%lu)", port_id);
4631 case MESSAGE_PROCEEDING:
4632 trace_header("PROCEEDING", dir);
4633 if (dir == DIRECTION_OUT)
4634 add_trace("to", NULL, "CH(%lu)", port_id);
4635 if (dir == DIRECTION_IN)
4636 add_trace("from", NULL, "CH(%lu)", port_id);
4640 case MESSAGE_ALERTING:
4641 trace_header("ALERTING", dir);
4642 if (dir == DIRECTION_OUT)
4643 add_trace("to", NULL, "CH(%lu)", port_id);
4644 if (dir == DIRECTION_IN)
4645 add_trace("from", NULL, "CH(%lu)", port_id);
4649 case MESSAGE_CONNECT:
4650 trace_header("CONNECT", dir);
4651 if (dir == DIRECTION_OUT)
4652 add_trace("to", NULL, "CH(%lu)", port_id);
4653 if (dir == DIRECTION_IN)
4654 add_trace("from", NULL, "CH(%lu)", port_id);
4655 if (param->connectinfo.extension[0])
4656 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4657 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4658 switch(param->connectinfo.present) {
4659 case INFO_PRESENT_RESTRICTED:
4660 add_trace("connect id", "present", "restricted");
4662 case INFO_PRESENT_ALLOWED:
4663 add_trace("connect id", "present", "allowed");
4666 add_trace("connect id", "present", "not available");
4668 if (param->connectinfo.display[0])
4669 add_trace("display", NULL, "%s", param->connectinfo.display);
4673 case MESSAGE_DISCONNECT:
4674 case MESSAGE_RELEASE:
4675 if (message_type == MESSAGE_DISCONNECT)
4676 trace_header("DISCONNECT", dir);
4678 trace_header("RELEASE", dir);
4679 if (dir == DIRECTION_OUT)
4680 add_trace("to", NULL, "CH(%lu)", port_id);
4681 if (dir == DIRECTION_IN)
4682 add_trace("from", NULL, "CH(%lu)", port_id);
4683 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4684 switch(param->disconnectinfo.location) {
4686 add_trace("cause", "location", "0-User");
4688 case LOCATION_PRIVATE_LOCAL:
4689 add_trace("cause", "location", "1-Local-PBX");
4691 case LOCATION_PUBLIC_LOCAL:
4692 add_trace("cause", "location", "2-Local-Exchange");
4694 case LOCATION_TRANSIT:
4695 add_trace("cause", "location", "3-Transit");
4697 case LOCATION_PUBLIC_REMOTE:
4698 add_trace("cause", "location", "4-Remote-Exchange");
4700 case LOCATION_PRIVATE_REMOTE:
4701 add_trace("cause", "location", "5-Remote-PBX");
4703 case LOCATION_INTERNATIONAL:
4704 add_trace("cause", "location", "7-International-Exchange");
4706 case LOCATION_BEYOND:
4707 add_trace("cause", "location", "10-Beyond-Interworking");
4710 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4712 if (param->disconnectinfo.display[0])
4713 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4717 case MESSAGE_NOTIFY:
4718 switch(param->notifyinfo.notify) {
4723 logtext = "USER_SUSPENDED";
4726 logtext = "BEARER_SERVICE_CHANGED";
4729 logtext = "USER_RESUMED";
4732 logtext = "CONFERENCE_ESTABLISHED";
4735 logtext = "CONFERENCE_DISCONNECTED";
4738 logtext = "OTHER_PARTY_ADDED";
4741 logtext = "ISOLATED";
4744 logtext = "REATTACHED";
4747 logtext = "OTHER_PARTY_ISOLATED";
4750 logtext = "OTHER_PARTY_REATTACHED";
4753 logtext = "OTHER_PARTY_SPLIT";
4756 logtext = "OTHER_PARTY_DISCONNECTED";
4759 logtext = "CONFERENCE_FLOATING";
4762 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4765 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4768 logtext = "CALL_IS_A_WAITING_CALL";
4771 logtext = "DIVERSION_ACTIVATED";
4774 logtext = "RESERVED_CT_1";
4777 logtext = "RESERVED_CT_2";
4780 logtext = "REVERSE_CHARGING";
4783 logtext = "REMOTE_HOLD";
4786 logtext = "REMOTE_RETRIEVAL";
4789 logtext = "CALL_IS_DIVERTING";
4792 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4796 trace_header("NOTIFY", dir);
4797 if (dir == DIRECTION_OUT)
4798 add_trace("to", NULL, "CH(%lu)", port_id);
4799 if (dir == DIRECTION_IN)
4800 add_trace("from", NULL, "CH(%lu)", port_id);
4801 if (param->notifyinfo.notify)
4802 add_trace("indicator", NULL, "%s", logtext);
4803 if (param->notifyinfo.id[0]) {
4804 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4805 switch(param->notifyinfo.present) {
4806 case INFO_PRESENT_RESTRICTED:
4807 add_trace("redir'on", "present", "restricted");
4809 case INFO_PRESENT_ALLOWED:
4810 add_trace("redir'on", "present", "allowed");
4813 add_trace("redir'on", "present", "not available");
4816 if (param->notifyinfo.display[0])
4817 add_trace("display", NULL, "%s", param->notifyinfo.display);
4821 case MESSAGE_PROGRESS:
4822 switch(param->progressinfo.progress) {
4824 logtext = "Call is not end to end ISDN";
4827 logtext = "Destination address is non-ISDN";
4830 logtext = "Origination address is non-ISDN";
4833 logtext = "Call has returned to the ISDN";
4836 logtext = "In-band info or pattern available";
4839 SPRINT(buffer, "%d", param->progressinfo.progress);
4843 trace_header("PROGRESS", dir);
4844 if (dir == DIRECTION_OUT)
4845 add_trace("to", NULL, "CH(%lu)", port_id);
4846 if (dir == DIRECTION_IN)
4847 add_trace("from", NULL, "CH(%lu)", port_id);
4848 add_trace("indicator", NULL, "%s", logtext);
4849 switch(param->progressinfo.location) {
4851 add_trace("cause", "location", "0-User");
4853 case LOCATION_PRIVATE_LOCAL:
4854 add_trace("cause", "location", "1-Local-PBX");
4856 case LOCATION_PUBLIC_LOCAL:
4857 add_trace("cause", "location", "2-Local-Exchange");
4859 case LOCATION_TRANSIT:
4860 add_trace("cause", "location", "3-Transit");
4862 case LOCATION_PUBLIC_REMOTE:
4863 add_trace("cause", "location", "4-Remote-Exchange");
4865 case LOCATION_PRIVATE_REMOTE:
4866 add_trace("cause", "location", "5-Remote-PBX");
4868 case LOCATION_INTERNATIONAL:
4869 add_trace("cause", "location", "7-International-Exchange");
4871 case LOCATION_BEYOND:
4872 add_trace("cause", "location", "10-Beyond-Interworking");
4875 add_trace("cause", "location", "%d", param->progressinfo.location);
4880 case MESSAGE_INFORMATION:
4881 trace_header("INFORMATION", dir);
4882 if (dir == DIRECTION_OUT)
4883 add_trace("to", NULL, "CH(%lu)", port_id);
4884 if (dir == DIRECTION_IN)
4885 add_trace("from", NULL, "CH(%lu)", port_id);
4886 if (param->information.id[0])
4887 add_trace("dialing", NULL, "%s", param->information.id);
4888 if (param->information.display[0])
4889 add_trace("display", NULL, "%s", param->information.display);
4890 if (param->information.sending_complete)
4891 add_trace("complete", NULL, "true", param->information.sending_complete);
4895 case MESSAGE_FACILITY:
4896 trace_header("FACILITY", dir);
4897 if (dir == DIRECTION_OUT)
4898 add_trace("to", NULL, "CH(%lu)", port_id);
4899 if (dir == DIRECTION_IN)
4900 add_trace("from", NULL, "CH(%lu)", port_id);
4905 trace_header("TONE", dir);
4906 if (dir == DIRECTION_OUT)
4907 add_trace("to", NULL, "CH(%lu)", port_id);
4908 if (dir == DIRECTION_IN)
4909 add_trace("from", NULL, "CH(%lu)", port_id);
4910 if (param->tone.name[0]) {
4911 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4912 add_trace("name", NULL, "%s", param->tone.name);
4914 add_trace("off", NULL, NULL);
4918 case MESSAGE_SUSPEND:
4919 case MESSAGE_RESUME:
4920 if (message_type == MESSAGE_SUSPEND)
4921 trace_header("SUSPEND", dir);
4923 trace_header("RESUME", dir);
4924 if (dir == DIRECTION_OUT)
4925 add_trace("to", NULL, "CH(%lu)", port_id);
4926 if (dir == DIRECTION_IN)
4927 add_trace("from", NULL, "CH(%lu)", port_id);
4928 if (param->parkinfo.len)
4929 add_trace("length", NULL, "%d", param->parkinfo.len);
4934 case MESSAGE_BCHANNEL:
4935 trace_header("BCHANNEL", dir);
4936 switch(param->bchannel.type) {
4937 case BCHANNEL_REQUEST:
4938 add_trace("type", NULL, "request");
4940 case BCHANNEL_ASSIGN:
4941 add_trace("type", NULL, "assign");
4943 case BCHANNEL_ASSIGN_ACK:
4944 add_trace("type", NULL, "assign_ack");
4946 case BCHANNEL_REMOVE:
4947 add_trace("type", NULL, "remove");
4949 case BCHANNEL_REMOVE_ACK:
4950 add_trace("type", NULL, "remove_ack");
4953 if (param->bchannel.addr)
4954 add_trace("address", NULL, "%x", param->bchannel.addr);
4960 if (param->threepty.begin)
4961 trace_header("Begin3PTY", dir);
4962 if (param->threepty.end)
4963 trace_header("End3PTY", dir);
4964 if (param->threepty.invoke)
4965 add_trace("action", NULL, "invoke");
4966 if (param->threepty.result)
4967 add_trace("action", NULL, "result");
4968 if (param->threepty.error)
4969 add_trace("action", NULL, "error");
4970 add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id);
4974 case MESSAGE_TRANSFER:
4975 trace_header("TRANSFER", dir);
4976 if (param->transfer.invoke)
4977 add_trace("action", NULL, "invoke");
4978 if (param->transfer.result)
4979 add_trace("action", NULL, "result");
4980 if (param->transfer.error)
4981 add_trace("action", NULL, "error");
4982 add_trace("invoke-id", NULL, "%d", param->transfer.invoke_id);
4986 case MESSAGE_DISABLE_DEJITTER:
4987 trace_header("DISBALE_DEJITTER", dir);
4989 add_trace("queue", NULL, "%d", param->queue);
4993 case MESSAGE_DOV_INDICATION:
4994 case MESSAGE_DOV_REQUEST:
4995 trace_header("Data-Over-Voice", dir);
4996 if (dir == DIRECTION_OUT)
4997 add_trace("to", NULL, "CH(%lu)", port_id);
4998 if (dir == DIRECTION_IN)
4999 add_trace("from", NULL, "CH(%lu)", port_id);
5001 char dov_str[param->dov.length + 1];
5002 memcpy(dov_str, param->dov.data, param->dov.length);
5003 dov_str[param->dov.length] = '\0';
5004 add_trace("string", NULL, "%s", dov_str);
5006 add_trace("type", NULL, "%d", param->dov.type);
5010 case MESSAGE_ENABLEKEYPAD:
5011 trace_header("ENABLEKEYPAD", dir);
5016 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
5020 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display, const struct param_transfer *transfer)
5022 struct lcr_msg *message;
5026 if (!portlist->port_id)
5029 if (!e_connectedmode) {
5030 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
5031 message->param.disconnectinfo.cause = cause;
5032 message->param.disconnectinfo.location = location;
5034 SCPY(message->param.disconnectinfo.display, display);
5036 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
5038 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
5040 SCPY(message->param.notifyinfo.display, display);
5042 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
5045 memcpy(&message->param.disconnectinfo.transfer, transfer, sizeof(struct param_transfer));
5047 message_put(message);
5048 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
5051 void EndpointAppPBX::dov_msg_write(union parameter *param, int sent)
5056 int __attribute__((__unused__)) rc;
5058 /* no write, if no log file given */
5059 if (!e_ext.dov_log[0])
5062 fp = fopen(e_ext.dov_log, "a");
5064 PERROR("EPOINT(%d) failed to open Data-Over-Voice log file '%s'\n", ea_endpoint->ep_serial, e_ext.dov_log);
5069 tm = localtime(&ti);
5070 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);
5074 fprintf(fp, "sent [%s] ", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
5076 fprintf(fp, "received [%s] ", e_dialinginfo.id);
5079 rc = fwrite(param->dov.data, param->dov.length, 1, fp);