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 rc = join_join_dss1(param->transfer.invoke_id);
2404 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TRANSFER);
2405 message->param.transfer.error = 1;
2406 message->param.transfer.invoke_id = param->transfer.invoke_id;
2407 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2408 message_put(message);
2413 /* port MESSAGE_SUSPEND */
2414 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2415 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2417 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2419 /* epoint is now parked */
2420 ea_endpoint->ep_park = 1;
2421 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2422 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2424 /* remove port relation */
2425 ea_endpoint->free_portlist(portlist);
2428 /* port MESSAGE_RESUME */
2429 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2430 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2432 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2434 /* epoint is now resumed */
2435 ea_endpoint->ep_park = 0;
2439 /* port MESSAGE_ENABLEKEYPAD */
2440 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2442 struct lcr_msg *message;
2444 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2446 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2447 memcpy(&message->param, param, sizeof(union parameter));
2448 message_put(message);
2452 /* port MESSAGE_DISABLE_DEJITTER */
2453 void EndpointAppPBX::port_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
2455 struct lcr_msg *message;
2457 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2459 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DISABLE_DEJITTER);
2460 memcpy(&message->param, param, sizeof(union parameter));
2461 message_put(message);
2464 /* port MESSAGE_DOV_INDICATION */
2465 void EndpointAppPBX::port_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
2467 struct lcr_msg *message;
2469 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2471 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_INDICATION);
2472 memcpy(&message->param, param, sizeof(union parameter));
2473 message_put(message);
2477 /* port MESSAGE_UPDATEBRIDGE */
2478 void EndpointAppPBX::port_updatebridge(struct port_list *portlist, int message_type, union parameter *param)
2480 struct lcr_msg *message;
2482 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_UPDATEBRIDGE);
2483 message_put(message);
2487 /* port MESSAGE_VOOTP */
2488 void EndpointAppPBX::port_vootp(struct port_list *portlist, int message_type, union parameter *param)
2490 if (param->vootp.failed)
2491 set_tone(ea_endpoint->ep_portlist, "crypt_off");
2495 /* port sends message to the endpoint
2497 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2499 struct port_list *portlist;
2501 portlist = ea_endpoint->ep_portlist;
2503 if (port_id == portlist->port_id)
2505 portlist = portlist->next;
2508 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);
2512 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2513 switch(message_type) {
2514 case MESSAGE_TONE_EOF: /* tone is end of file */
2515 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2517 if (e_action->index == ACTION_VBOX_PLAY) {
2520 if (e_action->index == ACTION_EFI) {
2526 case MESSAGE_TONE_COUNTER: /* counter info received */
2527 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);
2529 if (e_action->index == ACTION_VBOX_PLAY) {
2530 e_vbox_counter = param->counter.current;
2531 if (param->counter.max >= 0)
2532 e_vbox_counter_max = param->counter.max;
2536 /* PORT sends SETUP message */
2538 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);
2539 if (e_state!=EPOINT_STATE_IDLE) {
2540 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2543 port_setup(portlist, message_type, param);
2546 /* PORT sends INFORMATION message */
2547 case MESSAGE_INFORMATION: /* additional digits received */
2548 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);
2549 port_information(portlist, message_type, param);
2552 /* PORT sends FACILITY message */
2553 case MESSAGE_FACILITY:
2554 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2555 port_facility(portlist, message_type, param);
2559 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming 3PTY facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2560 port_3pty(portlist, message_type, param);
2563 case MESSAGE_TRANSFER:
2564 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming TRANSFER request (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2565 port_transfer(portlist, message_type, param);
2568 /* PORT sends DTMF message */
2569 case MESSAGE_DTMF: /* dtmf digits received */
2570 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);
2571 port_dtmf(portlist, message_type, param);
2574 /* PORT sends CRYPT message */
2575 case MESSAGE_CRYPT: /* crypt response received */
2576 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2577 port_crypt(portlist, message_type, param);
2580 /* PORT sends MORE message */
2581 case MESSAGE_OVERLAP:
2582 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);
2583 if (e_state != EPOINT_STATE_OUT_SETUP) {
2584 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);
2587 port_overlap(portlist, message_type, param);
2590 /* PORT sends PROCEEDING message */
2591 case MESSAGE_PROCEEDING: /* port is proceeding */
2592 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);
2593 if (e_state!=EPOINT_STATE_OUT_SETUP
2594 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2595 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);
2598 port_proceeding(portlist, message_type, param);
2601 /* PORT sends ALERTING message */
2602 case MESSAGE_ALERTING:
2603 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);
2604 if (e_state!=EPOINT_STATE_OUT_SETUP
2605 && e_state!=EPOINT_STATE_OUT_OVERLAP
2606 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2607 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);
2610 port_alerting(portlist, message_type, param);
2613 /* PORT sends CONNECT message */
2614 case MESSAGE_CONNECT:
2615 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);
2616 if (e_state!=EPOINT_STATE_OUT_SETUP
2617 && e_state!=EPOINT_STATE_OUT_OVERLAP
2618 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2619 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2620 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2623 port_connect(portlist, message_type, param);
2626 /* PORT sends DISCONNECT message */
2627 case MESSAGE_DISCONNECT: /* port is disconnected */
2628 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);
2629 port_disconnect_release(portlist, message_type, param);
2632 /* PORT sends a RELEASE message */
2633 case MESSAGE_RELEASE: /* port releases */
2634 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);
2635 /* portlist is release at port_disconnect_release, thanx Paul */
2636 port_disconnect_release(portlist, message_type, param);
2639 /* PORT sends a TIMEOUT message */
2640 case MESSAGE_TIMEOUT:
2641 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);
2642 port_timeout(portlist, message_type, param);
2643 break; /* release */
2645 /* PORT sends a NOTIFY message */
2646 case MESSAGE_NOTIFY:
2647 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);
2648 port_notify(portlist, message_type, param);
2651 /* PORT sends a PROGRESS message */
2652 case MESSAGE_PROGRESS:
2653 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);
2654 port_progress(portlist, message_type, param);
2657 /* PORT sends a SUSPEND message */
2658 case MESSAGE_SUSPEND:
2659 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);
2660 port_suspend(portlist, message_type, param);
2661 break; /* suspend */
2663 /* PORT sends a RESUME message */
2664 case MESSAGE_RESUME:
2665 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);
2666 port_resume(portlist, message_type, param);
2670 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2671 /* port assigns bchannel */
2672 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2673 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);
2674 /* only one port is expected to be connected to bchannel */
2675 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2676 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2680 /* PORT requests DTMF */
2681 case MESSAGE_ENABLEKEYPAD:
2682 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);
2683 port_enablekeypad(portlist, message_type, param);
2686 case MESSAGE_DISABLE_DEJITTER:
2687 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);
2688 port_disable_dejitter(portlist, message_type, param);
2691 case MESSAGE_UPDATEBRIDGE:
2692 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming updatebridge message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2693 port_updatebridge(portlist, message_type, param);
2697 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming vootp message (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2698 port_vootp(portlist, message_type, param);
2701 /* PORT indivated Data-Over-Voice */
2702 case MESSAGE_DOV_INDICATION:
2703 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);
2704 port_dov_indication(portlist, message_type, param);
2708 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);
2711 /* Note: this endpoint may be destroyed, so we MUST return */
2715 /* messages from join
2717 /* join MESSAGE_CRYPT */
2718 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2721 switch(param->crypt.type) {
2722 /* message from remote port to "crypt manager" */
2723 case CU_ACTK_REQ: /* activate key-exchange */
2724 case CU_ACTS_REQ: /* activate shared key */
2725 case CU_DACT_REQ: /* deactivate */
2726 case CU_INFO_REQ: /* request last info message */
2727 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2730 /* message from "crypt manager" to user */
2731 case CU_ACTK_CONF: /* key-echange done */
2732 case CU_ACTS_CONF: /* shared key done */
2733 case CU_DACT_CONF: /* deactivated */
2734 case CU_DACT_IND: /* deactivated */
2735 case CU_ERROR_IND: /* receive error message */
2736 case CU_INFO_IND: /* receive info message */
2737 case CU_INFO_CONF: /* receive info message */
2738 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2742 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);
2747 /* join MESSAGE_INFORMATION */
2748 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2750 struct lcr_msg *message;
2755 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2756 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2757 message_put(message);
2758 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2759 portlist = portlist->next;
2763 /* join MESSAGE_FACILITY */
2764 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2766 struct lcr_msg *message;
2768 if (!e_ext.facility && e_ext.number[0]) {
2773 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2774 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2775 message_put(message);
2776 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2777 portlist = portlist->next;
2781 /* join MESSAGE_MORE */
2782 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2784 struct lcr_msg *message;
2786 new_state(EPOINT_STATE_IN_OVERLAP);
2789 if (e_join_pattern && e_ext.own_setup) {
2790 /* disconnect audio */
2791 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2792 message->param.audiopath = 0;
2793 message_put(message);
2795 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2796 if (e_dialinginfo.id[0])
2797 set_tone(portlist, "dialing");
2799 set_tone(portlist, "dialtone");
2802 if (e_dialinginfo.id[0]) {
2803 set_tone(portlist, "dialing");
2805 if (e_ext.number[0])
2806 set_tone(portlist, "dialpbx");
2808 set_tone(portlist, "dialtone");
2812 /* join MESSAGE_PROCEEDING */
2813 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2815 struct lcr_msg *message;
2817 new_state(EPOINT_STATE_IN_PROCEEDING);
2819 /* own proceeding tone */
2820 if (e_join_pattern) {
2821 /* connect / disconnect audio */
2822 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2823 if (e_ext.own_proceeding)
2824 message->param.audiopath = 0;
2826 message->param.audiopath = 1;
2827 message_put(message);
2829 // UCPY(e_join_tone, "proceeding");
2831 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2832 message_put(message);
2833 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2835 set_tone(portlist, "proceeding");
2838 /* join MESSAGE_ALERTING */
2839 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2841 struct lcr_msg *message;
2843 new_state(EPOINT_STATE_IN_ALERTING);
2845 /* own alerting tone */
2846 if (e_join_pattern) {
2847 /* connect / disconnect audio */
2848 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2849 if (e_ext.own_alerting)
2850 message->param.audiopath = 0;
2852 message->param.audiopath = 1;
2853 message_put(message);
2856 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2857 message_put(message);
2858 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2860 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2861 set_tone(portlist, "ringing");
2864 if (e_ext.number[0])
2865 set_tone(portlist, "ringpbx");
2867 set_tone(portlist, "ringing");
2869 if (e_ext.number[0])
2870 e_dtmf = 1; /* allow dtmf */
2873 /* join MESSAGE_CONNECT */
2874 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2876 struct lcr_msg *message;
2879 new_state(EPOINT_STATE_CONNECT);
2880 // UCPY(e_join_tone, "");
2882 if (e_ext.number[0])
2883 e_dtmf = 1; /* allow dtmf */
2886 unsched_timer(&e_powerdial_timeout);
2887 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2889 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2890 memcpy(&message->param, param, sizeof(union parameter));
2892 /* screen clip if prefix is required */
2893 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2894 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2895 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2896 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2899 /* use internal caller id */
2900 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2901 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2902 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2905 /* handle restricted caller ids */
2906 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);
2907 /* display callerid if desired for extension */
2908 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));
2910 /* use conp, if enabld */
2911 // if (!e_ext.centrex)
2912 // message->param.connectinfo.name[0] = '\0';
2915 message_put(message);
2916 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2918 set_tone(portlist, NULL);
2920 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2921 message->param.audiopath = 1;
2922 message_put(message);
2926 /* if the remote answered, we listen to DOV message */
2927 if (e_ext.dov_log[0]) {
2928 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_DOV_LISTEN);
2929 message->param.dov.type = e_ext.dov_type;
2930 message_put(message);
2934 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2935 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2938 struct lcr_msg *message;
2939 struct port_list *portlist = NULL;
2943 /* be sure that we are active */
2945 e_tx_state = NOTIFY_STATE_ACTIVE;
2947 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2948 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2949 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2951 /* set time for power dialing */
2952 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2955 /* set redial tone */
2956 if (ea_endpoint->ep_portlist) {
2959 set_tone(ea_endpoint->ep_portlist, "redial");
2960 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);
2961 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2962 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2963 new_state(EPOINT_STATE_IN_PROCEEDING);
2964 if (ea_endpoint->ep_portlist) {
2965 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2966 message_put(message);
2967 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2969 /* caused the error, that the first knock sound was not there */
2970 /* set_tone(portlist, "proceeding"); */
2972 /* send display of powerdialing */
2973 if (e_ext.display_dialing) {
2974 portlist = ea_endpoint->ep_portlist;
2976 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2978 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2980 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2981 message_put(message);
2982 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2983 portlist = portlist->next;
2993 if ((e_state!=EPOINT_STATE_CONNECT
2994 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2995 && e_state!=EPOINT_STATE_IN_OVERLAP
2996 && e_state!=EPOINT_STATE_IN_PROCEEDING
2997 && e_state!=EPOINT_STATE_IN_ALERTING)
2998 || !ea_endpoint->ep_portlist) { /* or no port */
2999 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3000 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3001 return; /* must exit here */
3004 if (!e_join_cause) {
3005 e_join_cause = param->disconnectinfo.cause;
3006 e_join_location = param->disconnectinfo.location;
3009 /* on release we need the audio again! */
3010 if (message_type == MESSAGE_RELEASE) {
3012 ea_endpoint->ep_join_id = 0;
3014 /* disconnect and select tone */
3015 new_state(EPOINT_STATE_OUT_DISCONNECT);
3016 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3017 /* if own_cause, we must release the join */
3018 if (e_ext.own_cause /* own cause */
3019 || !e_join_pattern) { /* no patterns */
3020 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);
3021 if (message_type != MESSAGE_RELEASE)
3022 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3024 } else { /* else we enable audio */
3025 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3026 message->param.audiopath = 1;
3027 message_put(message);
3029 /* send disconnect message */
3030 SCPY(e_tone, cause);
3031 portlist = ea_endpoint->ep_portlist;
3033 set_tone(portlist, cause);
3034 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "", ¶m->disconnectinfo.transfer);
3035 portlist = portlist->next;
3039 /* join MESSAGE_SETUP */
3040 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3042 struct lcr_msg *message;
3043 // struct interface *interface;
3045 /* if we already in setup state, we just update the dialing with new digits */
3046 if (e_state == EPOINT_STATE_OUT_SETUP
3047 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3048 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3049 /* if digits changed, what we have already dialed */
3050 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3051 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);
3052 /* release all ports */
3053 while((portlist = ea_endpoint->ep_portlist)) {
3054 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3055 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3056 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3057 message_put(message);
3058 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3059 ea_endpoint->free_portlist(portlist);
3062 /* disconnect audio */
3063 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3064 message->param.audiopath = 0;
3065 message_put(message);
3067 /* get dialing info */
3068 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3069 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3070 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3071 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3072 new_state(EPOINT_STATE_OUT_OVERLAP);
3075 schedule_timer(&e_redial_timeout, 1, 0);
3078 /* if we have a pending redial, so we just adjust the dialing number */
3079 if (e_redial_timeout.active) {
3080 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);
3081 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3084 if (!ea_endpoint->ep_portlist) {
3085 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3087 if (ea_endpoint->ep_portlist->next) {
3088 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3090 if (e_state == EPOINT_STATE_OUT_SETUP) {
3092 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);
3093 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3096 /* get what we have not dialed yet */
3097 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));
3098 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3099 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3100 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3101 message_put(message);
3102 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3104 /* always store what we have dialed or queued */
3105 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3109 if (e_state != EPOINT_STATE_IDLE) {
3110 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3113 /* if an internal extension is dialed, copy that number */
3114 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3115 SCPY(e_ext.number, param->setup.dialinginfo.id);
3116 /* if an internal extension is dialed, get extension's info about caller */
3117 if (e_ext.number[0]) {
3118 if (!read_extension(&e_ext, e_ext.number)) {
3119 e_ext.number[0] = '\0';
3120 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3124 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3125 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3126 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3127 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3128 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3130 /* process (voice over) data calls */
3131 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3132 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3133 memset(&e_capainfo, 0, sizeof(e_capainfo));
3134 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3135 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3136 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3139 new_state(EPOINT_STATE_OUT_SETUP);
3140 /* call special setup routine */
3144 /* join MESSAGE_mISDNSIGNAL */
3145 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3147 struct lcr_msg *message;
3150 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3151 memcpy(&message->param, param, sizeof(union parameter));
3152 message_put(message);
3153 portlist = portlist->next;
3157 /* join MESSAGE_BRIDE */
3158 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3160 struct lcr_msg *message;
3163 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3164 memcpy(&message->param, param, sizeof(union parameter));
3165 message_put(message);
3166 portlist = portlist->next;
3170 /* join MESSAGE_NOTIFY */
3171 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3173 struct lcr_msg *message;
3176 if (param->notifyinfo.notify) {
3177 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3178 // /* if notification was generated locally, we turn hold music on/off */
3179 // if (param->notifyinfo.local)
3180 // 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)
3184 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3185 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3187 set_tone(portlist, "");
3188 portlist = portlist->next;
3191 portlist = ea_endpoint->ep_portlist;
3196 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3198 set_tone(portlist, "hold");
3199 portlist = portlist->next;
3201 portlist = ea_endpoint->ep_portlist;
3206 /* save new state */
3207 e_tx_state = new_state;
3210 /* notify port(s) about it */
3212 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3213 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3214 /* handle restricted caller ids */
3215 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3216 /* display callerid if desired for extension */
3217 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));
3218 message_put(message);
3219 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3220 portlist = portlist->next;
3224 /* join MESSAGE_DTMF */
3225 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3227 struct lcr_msg *message;
3230 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3231 memcpy(&message->param, param, sizeof(union parameter));
3232 message_put(message);
3233 portlist = portlist->next;
3237 /* join MESSAGE_DISABLE_DEJITTER */
3238 void EndpointAppPBX::join_disable_dejitter(struct port_list *portlist, int message_type, union parameter *param)
3240 struct lcr_msg *message;
3243 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISABLE_DEJITTER);
3244 memcpy(&message->param, param, sizeof(union parameter));
3245 message_put(message);
3246 portlist = portlist->next;
3250 /* join MESSAGE_DOV_INDICATION */
3251 void EndpointAppPBX::join_dov_indication(struct port_list *portlist, int message_type, union parameter *param)
3253 dov_msg_write(param, 0);
3256 /* join MESSAGE_DOV_REQUEST */
3257 void EndpointAppPBX::join_dov_request(struct port_list *portlist, int message_type, union parameter *param)
3259 struct lcr_msg *message;
3261 /* don't send DOV from estension to extension */
3262 if (e_ext.number[0])
3266 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_REQUEST);
3267 memcpy(&message->param, param, sizeof(union parameter));
3268 message_put(message);
3269 logmessage(message_type, param, portlist->port_id, DIRECTION_OUT);
3270 portlist = portlist->next;
3274 /* join MESSAGE_DOV_LISTEN */
3275 void EndpointAppPBX::join_dov_listen(struct port_list *portlist, int message_type, union parameter *param)
3277 struct lcr_msg *message;
3280 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DOV_LISTEN);
3281 memcpy(&message->param, param, sizeof(union parameter));
3282 message_put(message);
3283 portlist = portlist->next;
3287 /* JOIN sends messages to the endpoint
3289 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3291 struct port_list *portlist;
3292 struct lcr_msg *message;
3295 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3299 portlist = ea_endpoint->ep_portlist;
3301 // 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);
3302 switch(message_type) {
3303 /* JOIN SENDS TONE message */
3305 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);
3306 set_tone(portlist, param->tone.name);
3309 /* JOIN SENDS CRYPT message */
3311 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);
3312 join_crypt(portlist, message_type, param);
3315 /* JOIN sends INFORMATION message */
3316 case MESSAGE_INFORMATION:
3317 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);
3318 join_information(portlist, message_type, param);
3321 /* JOIN sends FACILITY message */
3322 case MESSAGE_FACILITY:
3323 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);
3324 join_facility(portlist, message_type, param);
3327 /* JOIN sends OVERLAP message */
3328 case MESSAGE_OVERLAP:
3329 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);
3330 if (e_state!=EPOINT_STATE_IN_SETUP
3331 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3332 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3335 join_overlap(portlist, message_type, param);
3338 /* JOIN sends PROCEEDING message */
3339 case MESSAGE_PROCEEDING:
3340 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);
3341 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3342 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3345 join_proceeding(portlist, message_type, param);
3348 /* JOIN sends ALERTING message */
3349 case MESSAGE_ALERTING:
3350 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);
3351 if (e_state!=EPOINT_STATE_IN_OVERLAP
3352 && e_state!=EPOINT_STATE_IN_PROCEEDING
3353 && e_state!=EPOINT_STATE_IN_ALERTING /* second alerting */
3354 && e_state!=EPOINT_STATE_CONNECT) { /* alerting after transfer */
3355 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3358 join_alerting(portlist, message_type, param);
3361 /* JOIN sends CONNECT message */
3362 case MESSAGE_CONNECT:
3363 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);
3364 if (e_state!=EPOINT_STATE_IN_OVERLAP
3365 && e_state!=EPOINT_STATE_IN_PROCEEDING
3366 && e_state!=EPOINT_STATE_IN_ALERTING) {
3367 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3370 join_connect(portlist, message_type, param);
3373 /* JOIN sends DISCONNECT/RELEASE message */
3374 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3375 case MESSAGE_RELEASE: /* JOIN releases */
3376 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);
3377 join_disconnect_release(message_type, param);
3380 /* JOIN sends SETUP message */
3382 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);
3383 join_setup(portlist, message_type, param);
3386 /* JOIN sends special mISDNSIGNAL message */
3387 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3388 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);
3389 join_mISDNsignal(portlist, message_type, param);
3392 /* JOIN sends bridge message */
3393 case MESSAGE_BRIDGE: /* bride message to port */
3394 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);
3395 join_bridge(portlist, message_type, param);
3398 /* JOIN has pattern available */
3399 case MESSAGE_PATTERN: /* indicating pattern available */
3400 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);
3401 if (!e_join_pattern) {
3402 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3406 set_tone(portlist, NULL);
3407 portlist = portlist->next;
3409 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3410 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3411 message->param.audiopath = 1;
3412 message_put(message);
3416 /* JOIN has no pattern available */
3417 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3418 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);
3419 if (e_join_pattern) {
3420 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3422 /* disconnect our audio tx and rx */
3423 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3424 message->param.audiopath = 0;
3425 message_put(message);
3430 /* JOIN (dunno at the moment) */
3431 case MESSAGE_REMOTE_AUDIO:
3432 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);
3433 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3434 message->param.audiopath = param->channel;
3435 message_put(message);
3439 /* JOIN sends a notify message */
3440 case MESSAGE_NOTIFY:
3441 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);
3442 join_notify(portlist, message_type, param);
3445 /* JOIN wants keypad / dtmf */
3446 case MESSAGE_ENABLEKEYPAD:
3447 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);
3450 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3454 /* JOIN sends a DTMF message */
3456 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);
3457 join_dtmf(portlist, message_type, param);
3460 /* JOIN sends a DISABLE_DEJITTER message */
3461 case MESSAGE_DISABLE_DEJITTER:
3462 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);
3463 join_disable_dejitter(portlist, message_type, param);
3466 /* JOIN sends a Data-Over-Voice message indication */
3467 case MESSAGE_DOV_INDICATION:
3468 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);
3469 join_dov_indication(portlist, message_type, param);
3472 /* JOIN sends a Data-Over-Voice message request */
3473 case MESSAGE_DOV_REQUEST:
3474 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);
3475 join_dov_request(portlist, message_type, param);
3478 /* JOIN sends a Data-Over-Voice listen order */
3479 case MESSAGE_DOV_LISTEN:
3480 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);
3481 join_dov_listen(portlist, message_type, param);
3485 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);
3490 /* pick_join will connect the first incoming call found. the endpoint
3491 * will receivce a MESSAGE_CONNECT.
3493 int match_list(char *list, char *item)
3495 char *end, *next = NULL;
3497 /* no list make matching */
3502 /* eliminate white spaces */
3503 while (*list > '\0' && *list <= ' ')
3509 /* if end of list is reached, we return */
3510 if (list[0] == '\0')
3512 /* if we have more than one entry (left) */
3513 if ((end = strchr(list, ',')))
3516 next = end = strchr(list, '\0');
3517 while (*(end-1) <= ' ')
3519 /* if string part matches item */
3520 if (!strncmp(list, item, end-list))
3526 void EndpointAppPBX::pick_join(char *extensions)
3528 struct lcr_msg *message;
3529 struct port_list *portlist;
3531 class EndpointAppPBX *eapp, *found;
3533 class JoinPBX *joinpbx;
3534 struct join_relation *relation;
3536 /* find an endpoint that is ringing internally or vbox with higher priority */
3538 eapp = apppbx_first;
3540 if (eapp!=this && ea_endpoint->ep_portlist) {
3541 portlist = eapp->ea_endpoint->ep_portlist;
3543 if ((port = find_port_id(portlist->port_id))) {
3544 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3545 if (match_list(extensions, eapp->e_ext.number)) {
3550 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3551 && port->p_state==PORT_STATE_OUT_ALERTING)
3552 if (match_list(extensions, eapp->e_ext.number)) {
3556 portlist = portlist->next;
3564 /* if no endpoint found */
3566 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);
3568 set_tone(ea_endpoint->ep_portlist, "cause_10");
3569 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "", NULL);
3570 new_state(EPOINT_STATE_OUT_DISCONNECT);
3575 if (ea_endpoint->ep_join_id) {
3576 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3579 if (!eapp->ea_endpoint->ep_join_id) {
3580 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3583 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3585 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3588 if (join->j_type != JOIN_TYPE_PBX) {
3589 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3592 joinpbx = (class JoinPBX *)join;
3593 relation = joinpbx->j_relation;
3595 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3598 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3599 relation = relation->next;
3601 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3606 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3608 if (options.deb & DEBUG_EPOINT) {
3609 class Join *debug_c = join_first;
3610 class Endpoint *debug_e = epoint_first;
3611 class Port *debug_p = port_first;
3613 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3615 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3617 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3618 debug_c = debug_c->next;
3620 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3622 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3623 debug_e = debug_e->next;
3625 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3627 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3628 debug_p = debug_p->next;
3633 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3634 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3635 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3637 /* connnecting our endpoint */
3638 new_state(EPOINT_STATE_CONNECT);
3639 if (e_ext.number[0])
3641 set_tone(ea_endpoint->ep_portlist, NULL);
3643 /* now we send a release to the ringing endpoint */
3644 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3645 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3646 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3647 message_put(message);
3649 /* we send a connect to the join with our caller id */
3650 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3651 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3652 message->param.connectinfo.present = e_callerinfo.present;
3653 message->param.connectinfo.screen = e_callerinfo.screen;
3654 message->param.connectinfo.itype = e_callerinfo.itype;
3655 message->param.connectinfo.ntype = e_callerinfo.ntype;
3656 message_put(message);
3658 /* we send a connect to our port with the remote callerid */
3659 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3660 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3661 message->param.connectinfo.present = eapp->e_callerinfo.present;
3662 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3663 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3664 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3665 /* handle restricted caller ids */
3666 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);
3667 /* display callerid if desired for extension */
3668 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));
3669 message_put(message);
3671 /* we send a connect to the audio path (not for vbox) */
3672 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3673 message->param.audiopath = 1;
3674 message_put(message);
3676 /* beeing paranoid, we make call update */
3677 trigger_work(&joinpbx->j_updatebridge);
3679 if (options.deb & DEBUG_EPOINT) {
3680 class Join *debug_c = join_first;
3681 class Endpoint *debug_e = epoint_first;
3682 class Port *debug_p = port_first;
3684 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3686 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3688 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3689 debug_c = debug_c->next;
3691 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3693 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3694 debug_e = debug_e->next;
3696 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3698 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3699 debug_p = debug_p->next;
3705 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3707 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;
3717 class Pdss1 *our_pdss1, *other_pdss1;
3718 class Endpoint *temp_epoint;
3720 /* are we a candidate to join a join? */
3721 our_join = find_join_id(ea_endpoint->ep_join_id);
3723 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3726 if (our_join->j_type != JOIN_TYPE_PBX) {
3727 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3730 our_joinpbx = (class JoinPBX *)our_join;
3731 if (!ea_endpoint->ep_portlist) {
3732 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3735 if (!e_ext.number[0]) {
3736 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3739 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3741 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3744 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3745 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3748 our_pdss1 = (class Pdss1 *)our_port;
3750 /* find an endpoint that has the same mISDNport/ces that we are on */
3751 other_eapp = apppbx_first;
3753 if (other_eapp == this) {
3754 other_eapp = other_eapp->next;
3757 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);
3758 if (other_eapp->e_ext.number[0] /* has terminal */
3759 && other_eapp->ea_endpoint->ep_portlist /* has port */
3760 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3761 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3762 if (other_port) { /* port still exists */
3763 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3764 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3765 other_pdss1 = (class Pdss1 *)other_port;
3766 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_m_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
3767 if (1 //other_pdss1->p_m_hold /* port is on hold */
3768 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3769 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3772 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3775 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3778 other_eapp = other_eapp->next;
3781 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3784 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3786 /* if we have the same join */
3787 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3788 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3791 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3793 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3796 if (other_join->j_type != JOIN_TYPE_PBX) {
3797 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3800 other_joinpbx = (class JoinPBX *)other_join;
3801 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3802 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3806 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
3807 if (our_port->p_hold && !other_port->p_hold) {
3808 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);
3809 remove_eapp_hold = this;
3810 remove_eapp_active = other_eapp;
3811 remove_join = our_join;
3812 remove_joinpbx = our_joinpbx;
3813 add_join = other_join;
3814 add_joinpbx = other_joinpbx;
3816 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);
3817 remove_eapp_hold = other_eapp;
3818 remove_eapp_active = this;
3819 remove_join = other_join;
3820 remove_joinpbx = other_joinpbx;
3821 add_join = our_join;
3822 add_joinpbx = our_joinpbx;
3825 /* remove relation to endpoint for join on hold */
3826 remove_relation = remove_joinpbx->j_relation;
3827 remove_relation_pointer = &remove_joinpbx->j_relation;
3828 while(remove_relation) {
3829 if (remove_relation->epoint_id == remove_eapp_hold->ea_endpoint->ep_serial) {
3830 /* detach endpoint on hold */
3831 *remove_relation_pointer = remove_relation->next;
3832 FREE(remove_relation, sizeof(struct join_relation));
3834 remove_relation = *remove_relation_pointer;
3835 remove_eapp_hold->ea_endpoint->ep_join_id = 0;
3839 /* change join/hold pointer of endpoint to the new join */
3840 temp_epoint = find_epoint_id(remove_relation->epoint_id);
3842 if (temp_epoint->ep_join_id == remove_join->j_serial)
3843 temp_epoint->ep_join_id = add_join->j_serial;
3846 remove_relation_pointer = &remove_relation->next;
3847 remove_relation = remove_relation->next;
3849 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint (hold) removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3851 if (invoke_id >= 0) {
3852 /* remove relation to endpoint for active join */
3853 remove_relation = add_joinpbx->j_relation;
3854 remove_relation_pointer = &add_joinpbx->j_relation;
3855 while(remove_relation) {
3856 if (remove_relation->epoint_id == remove_eapp_active->ea_endpoint->ep_serial) {
3857 /* detach active endpoint */
3858 *remove_relation_pointer = remove_relation->next;
3859 FREE(remove_relation, sizeof(struct join_relation));
3861 remove_relation = *remove_relation_pointer;
3862 remove_eapp_active->ea_endpoint->ep_join_id = 0;
3866 remove_relation_pointer = &remove_relation->next;
3867 remove_relation = remove_relation->next;
3869 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint (active) removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
3871 /* if active endpoint is in alerting state, send alerting message to join */
3872 if (remove_eapp_active->e_state == EPOINT_STATE_IN_ALERTING) {
3873 if (add_joinpbx->j_relation && !add_joinpbx->j_relation->next) {
3874 /* if channel state indicateds "audio" (1), we tell the other endpoint that patterns are available */
3875 if (add_joinpbx->j_relation->channel_state) {
3876 message = message_create(add_joinpbx->j_relation->epoint_id, add_join->j_serial, EPOINT_TO_JOIN, MESSAGE_PATTERN);
3877 message_put(message);
3879 message = message_create(add_joinpbx->j_relation->epoint_id, add_join->j_serial, EPOINT_TO_JOIN, MESSAGE_ALERTING);
3880 message_put(message);
3885 /* join call relations: we add the members of the join on hold to the active join */
3886 add_relation = add_joinpbx->j_relation;
3887 add_relation_pointer = &add_joinpbx->j_relation;
3888 while(add_relation) {
3889 add_relation_pointer = &add_relation->next;
3890 add_relation = add_relation->next;
3892 *add_relation_pointer = remove_joinpbx->j_relation;
3893 remove_joinpbx->j_relation = NULL;
3894 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3896 /* release endpoint on hold */
3897 message = message_create(remove_joinpbx->j_serial, remove_eapp_hold->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3898 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3899 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3900 if (invoke_id >= 0) {
3901 /* send the result with disconnect message to the invoking endpoint */
3902 if (remove_eapp_hold->ea_endpoint->ep_serial == ea_endpoint->ep_serial) {
3903 message->param.disconnectinfo.transfer.result = 1;
3904 message->param.disconnectinfo.transfer.invoke_id = invoke_id;
3907 message_put(message);
3909 if (invoke_id >= 0) {
3910 /* release active endpoint */
3911 message = message_create(add_joinpbx->j_serial, remove_eapp_active->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3912 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3913 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3914 /* send the result with disconnect message to the invoking endpoint */
3915 if (remove_eapp_active->ea_endpoint->ep_serial == ea_endpoint->ep_serial) {
3916 message->param.disconnectinfo.transfer.result = 1;
3917 message->param.disconnectinfo.transfer.invoke_id = invoke_id;
3919 message_put(message);
3922 /* if we are not a partyline, we get partyline state from other join */
3923 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
3925 /* remove empty join */
3927 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
3929 /* mixer must update */
3930 trigger_work(&add_joinpbx->j_updatebridge);
3932 /* we send a retrieve to that endpoint */
3933 // mixer will update the hold-state of the join and send it to the endpoints is changes
3935 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3941 /* join calls (look for a join that is on hold (same fxs interface/terminal))
3943 int EndpointAppPBX::join_join_fxs(void)
3946 struct lcr_msg *message;
3947 struct join_relation *add_relation, *remove_relation;
3948 struct join_relation **add_relation_pointer, **remove_relation_pointer;
3949 class Join *our_join, *other_join, *add_join, *remove_join;
3950 class JoinPBX *our_joinpbx, *other_joinpbx, *add_joinpbx, *remove_joinpbx;
3951 class EndpointAppPBX *other_eapp, *remove_eapp;
3952 class Port *our_port, *other_port;
3953 class Pfxs *our_fxs, *other_fxs;
3954 class Endpoint *temp_epoint;
3956 /* are we a candidate to join a join? */
3957 our_join = find_join_id(ea_endpoint->ep_join_id);
3959 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3962 if (our_join->j_type != JOIN_TYPE_PBX) {
3963 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3966 our_joinpbx = (class JoinPBX *)our_join;
3967 if (!ea_endpoint->ep_portlist) {
3968 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3971 if (!e_ext.number[0]) {
3972 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3975 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3977 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3980 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
3981 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not fxs.\n", ea_endpoint->ep_serial);
3984 our_fxs = (class Pfxs *)our_port;
3986 /* find an endpoint that has the same mISDNport that we are on */
3987 other_eapp = apppbx_first;
3989 if (other_eapp == this) {
3990 other_eapp = other_eapp->next;
3993 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);
3994 if (other_eapp->e_ext.number[0] /* has terminal */
3995 && other_eapp->ea_endpoint->ep_portlist /* has port */
3996 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3997 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3998 if (other_port) { /* port still exists */
3999 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4000 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is FXS */
4001 other_fxs = (class Pfxs *)other_port;
4002 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);
4003 if (1 //other_fxs->p_hold /* port is on hold */
4004 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same isdn interface */
4007 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4010 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4013 other_eapp = other_eapp->next;
4016 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4019 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4021 /* if we have the same join */
4022 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4023 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4026 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4028 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4031 if (other_join->j_type != JOIN_TYPE_PBX) {
4032 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4035 other_joinpbx = (class JoinPBX *)other_join;
4036 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4037 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4041 /* now find out which is ACTIVE-IDLE and which is ACTIVE-HELD */
4042 if (our_port->p_hold && !other_port->p_hold) {
4043 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);
4045 remove_join = our_join;
4046 remove_joinpbx = our_joinpbx;
4047 add_join = other_join;
4048 add_joinpbx = other_joinpbx;
4050 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);
4051 remove_eapp = other_eapp;
4052 remove_join = other_join;
4053 remove_joinpbx = other_joinpbx;
4054 add_join = our_join;
4055 add_joinpbx = our_joinpbx;
4058 /* remove relation to endpoint for join on hold */
4059 remove_relation = remove_joinpbx->j_relation;
4060 remove_relation_pointer = &remove_joinpbx->j_relation;
4061 while(remove_relation) {
4062 if (remove_relation->epoint_id == remove_eapp->ea_endpoint->ep_serial) {
4063 /* detach other endpoint */
4064 *remove_relation_pointer = remove_relation->next;
4065 FREE(remove_relation, sizeof(struct join_relation));
4067 remove_relation = *remove_relation_pointer;
4068 remove_eapp->ea_endpoint->ep_join_id = 0;
4072 /* change join/hold pointer of endpoint to the new join */
4073 temp_epoint = find_epoint_id(remove_relation->epoint_id);
4075 if (temp_epoint->ep_join_id == remove_join->j_serial)
4076 temp_epoint->ep_join_id = add_join->j_serial;
4079 remove_relation_pointer = &remove_relation->next;
4080 remove_relation = remove_relation->next;
4082 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint removed, other enpoints on join relinked.\n", ea_endpoint->ep_serial);
4084 /* join call relations */
4085 add_relation = add_joinpbx->j_relation;
4086 add_relation_pointer = &add_joinpbx->j_relation;
4087 while(add_relation) {
4088 add_relation_pointer = &add_relation->next;
4089 add_relation = add_relation->next;
4091 *add_relation_pointer = remove_joinpbx->j_relation;
4092 remove_joinpbx->j_relation = NULL;
4093 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
4095 /* release endpoint */
4096 message = message_create(remove_joinpbx->j_serial, remove_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
4097 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
4098 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
4099 message_put(message);
4101 /* if we are not a partyline, we get partyline state from other join */
4102 add_joinpbx->j_partyline += remove_joinpbx->j_partyline;
4104 /* remove empty join */
4106 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)join completely removed!\n", ea_endpoint->ep_serial);
4108 /* mixer must update */
4109 trigger_work(&add_joinpbx->j_updatebridge);
4111 /* we send a retrieve to that endpoint */
4112 // mixer will update the hold-state of the join and send it to the endpoints is changes
4114 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4120 int EndpointAppPBX::join_3pty_dss1(void)
4123 class Join *our_join, *other_join;
4124 class JoinPBX *our_joinpbx, *other_joinpbx;
4125 class EndpointAppPBX *other_eapp;
4126 class Port *our_port, *other_port;
4127 class Pdss1 *our_pdss1, *other_pdss1;
4129 /* are we a candidate to join a join? */
4130 our_join = find_join_id(ea_endpoint->ep_join_id);
4132 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4135 if (our_join->j_type != JOIN_TYPE_PBX) {
4136 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4139 our_joinpbx = (class JoinPBX *)our_join;
4140 if (!ea_endpoint->ep_portlist) {
4141 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4144 if (!e_ext.number[0]) {
4145 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4148 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4150 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4153 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
4154 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
4157 our_pdss1 = (class Pdss1 *)our_port;
4159 /* find an endpoint that has the same mISDNport/ces that we are on */
4160 other_eapp = apppbx_first;
4162 if (other_eapp == this) {
4163 other_eapp = other_eapp->next;
4166 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);
4167 if (other_eapp->e_ext.number[0] /* has terminal */
4168 && other_eapp->ea_endpoint->ep_portlist /* has port */
4169 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4170 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4171 if (other_port) { /* port still exists */
4172 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
4173 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
4174 other_pdss1 = (class Pdss1 *)other_port;
4175 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of type isdn! comparing our portnum=%d with other's portnum=%d hold=%s ces=%d\n", ea_endpoint->ep_serial, our_pdss1->p_m_mISDNport->portnum, other_pdss1->p_m_mISDNport->portnum, (other_pdss1->p_m_hold)?"YES":"NO", other_pdss1->p_m_d_ces);
4176 if (1 //other_pdss1->p_m_hold /* port is on hold */
4177 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
4178 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
4181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4184 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4187 other_eapp = other_eapp->next;
4190 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
4193 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4195 /* if we have the same join */
4196 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4197 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4200 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4202 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4205 if (other_join->j_type != JOIN_TYPE_PBX) {
4206 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4209 other_joinpbx = (class JoinPBX *)other_join;
4210 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4211 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4215 if (our_joinpbx->j_3pty) {
4216 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4219 if (other_joinpbx->j_3pty) {
4220 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4224 /* set 3PTY bridge */
4225 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4226 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4228 /* mixer must update */
4229 trigger_work(&our_joinpbx->j_updatebridge);
4230 trigger_work(&other_joinpbx->j_updatebridge);
4232 /* we send a retrieve to that endpoint */
4233 // mixer will update the hold-state of the join and send it to the endpoints is changes
4235 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4241 int EndpointAppPBX::join_3pty_fxs(void)
4244 class Join *our_join, *other_join;
4245 class JoinPBX *our_joinpbx, *other_joinpbx;
4246 class EndpointAppPBX *other_eapp;
4247 class Port *our_port, *other_port;
4248 class Pfxs *our_fxs, *other_fxs;
4250 /* are we a candidate to join a join? */
4251 our_join = find_join_id(ea_endpoint->ep_join_id);
4253 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4256 if (our_join->j_type != JOIN_TYPE_PBX) {
4257 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
4260 our_joinpbx = (class JoinPBX *)our_join;
4261 if (!ea_endpoint->ep_portlist) {
4262 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
4265 if (!e_ext.number[0]) {
4266 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
4269 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
4271 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
4274 if ((our_port->p_type & PORT_CLASS_POTS_MASK) != PORT_CLASS_POTS_FXS) {
4275 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not FXS pots.\n", ea_endpoint->ep_serial);
4278 our_fxs = (class Pfxs *)our_port;
4280 /* find an endpoint that has the same mISDNport that we are on */
4281 other_eapp = apppbx_first;
4283 if (other_eapp == this) {
4284 other_eapp = other_eapp->next;
4287 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);
4288 if (other_eapp->e_ext.number[0] /* has terminal */
4289 && other_eapp->ea_endpoint->ep_portlist /* has port */
4290 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
4291 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
4292 if (other_port) { /* port still exists */
4293 if (other_port->p_type==PORT_TYPE_POTS_FXS_OUT
4294 || other_port->p_type==PORT_TYPE_POTS_FXS_IN) { /* port is isdn nt-mode */
4295 other_fxs = (class Pfxs *)other_port;
4296 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);
4297 if (1 //other_fxs->p_hold /* port is on hold */
4298 && other_fxs->p_m_mISDNport == our_fxs->p_m_mISDNport) /* same pots interface */
4301 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
4304 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
4307 other_eapp = other_eapp->next;
4310 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same FXS terminal.\n", ea_endpoint->ep_serial);
4313 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
4315 /* if we have the same join */
4316 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
4317 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
4320 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
4322 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4325 if (other_join->j_type != JOIN_TYPE_PBX) {
4326 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
4329 other_joinpbx = (class JoinPBX *)other_join;
4330 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
4331 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
4335 if (our_joinpbx->j_3pty) {
4336 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join already doing 3PTY.\n", ea_endpoint->ep_serial);
4339 if (other_joinpbx->j_3pty) {
4340 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join already doing 3PTY.\n", ea_endpoint->ep_serial);
4344 /* set 3PTY bridge */
4345 other_joinpbx->j_3pty = our_joinpbx->j_serial;
4346 our_joinpbx->j_3pty = other_joinpbx->j_serial;
4348 /* mixer must update */
4349 trigger_work(&our_joinpbx->j_updatebridge);
4350 trigger_work(&other_joinpbx->j_updatebridge);
4352 /* we send a retrieve to that endpoint */
4353 // mixer will update the hold-state of the join and send it to the endpoints is changes
4355 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4361 int EndpointAppPBX::split_3pty(void)
4364 class Join *our_join, *other_join;
4365 class JoinPBX *our_joinpbx, *other_joinpbx;
4367 /* are we a candidate to join a join? */
4368 our_join = find_join_id(ea_endpoint->ep_join_id);
4370 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4373 if (our_join->j_type != JOIN_TYPE_PBX) {
4374 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4377 our_joinpbx = (class JoinPBX *)our_join;
4379 if (!our_joinpbx->j_3pty) {
4380 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: we don't have a 3PTY.\n", ea_endpoint->ep_serial);
4384 other_join = find_join_id(our_joinpbx->j_3pty);
4386 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
4389 if (other_join->j_type != JOIN_TYPE_PBX) {
4390 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: join is not a pbx join.\n", ea_endpoint->ep_serial);
4393 other_joinpbx = (class JoinPBX *)other_join;
4395 our_joinpbx->j_3pty = 0;
4396 other_joinpbx->j_3pty = 0;
4398 /* mixer must update */
4399 trigger_work(&our_joinpbx->j_updatebridge);
4400 trigger_work(&other_joinpbx->j_updatebridge);
4402 /* we send a retrieve to that endpoint */
4403 // mixer will update the hold-state of the join and send it to the endpoints is changes
4405 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot split: no mISDN support anyway.\n", ea_endpoint->ep_serial);
4411 /* check if we have an external call
4412 * this is used to check for encryption ability
4414 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
4416 struct join_relation *relation;
4418 class JoinPBX *joinpbx;
4419 class Endpoint *epoint;
4421 /* some paranoia check */
4422 if (!ea_endpoint->ep_portlist) {
4423 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4424 *errstr = "No Call";
4427 if (!e_ext.number[0]) {
4428 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4429 *errstr = "No Call";
4433 /* check if we have a join with 2 parties */
4434 join = find_join_id(ea_endpoint->ep_join_id);
4436 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
4437 *errstr = "No Call";
4440 if (join->j_type != JOIN_TYPE_PBX) {
4441 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4442 *errstr = "No PBX Call";
4445 joinpbx = (class JoinPBX *)join;
4446 relation = joinpbx->j_relation;
4448 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4449 *errstr = "No Call";
4452 if (!relation->next) {
4453 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4454 *errstr = "No Call";
4457 if (relation->next->next) {
4458 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4459 *errstr = "Err: Conference";
4462 if (relation->epoint_id == ea_endpoint->ep_serial) {
4463 relation = relation->next;
4464 if (relation->epoint_id == ea_endpoint->ep_serial) {
4465 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4466 *errstr = "Software Error";
4471 /* check remote port for external call */
4472 epoint = find_epoint_id(relation->epoint_id);
4474 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4475 *errstr = "No Call";
4478 if (!epoint->ep_portlist) {
4479 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4480 *errstr = "No Call";
4483 *port = find_port_id(epoint->ep_portlist->port_id);
4485 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4486 *errstr = "No Call";
4489 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4490 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4491 *errstr = "No Ext Call";
4494 if ((*port)->p_state != PORT_STATE_CONNECT) {
4495 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4496 *errstr = "No Ext Connect";
4502 int EndpointAppPBX::vootp_on(int on)
4505 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4507 if (!e_ext.otp_ident[0]) {
4508 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4511 if(ea_endpoint->ep_portlist) {
4512 struct lcr_msg *message;
4514 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VOOTP);
4515 message->param.vootp.enable = on;
4516 SCPY(message->param.vootp.id, e_ext.otp_ident);
4517 message_put(message);
4520 set_tone(ea_endpoint->ep_portlist, "crypt_off");
4526 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4528 const char *logtext = "unknown";
4531 switch(message_type) {
4533 trace_header("SETUP", dir);
4534 if (dir == DIRECTION_OUT)
4535 add_trace("to", NULL, "CH(%lu)", port_id);
4536 if (dir == DIRECTION_IN)
4537 add_trace("from", NULL, "CH(%lu)", port_id);
4538 if (param->setup.callerinfo.extension[0])
4539 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4540 if (param->setup.callerinfo.interface[0])
4541 add_trace("interface", "from", "%s", param->setup.callerinfo.interface);
4542 if (param->setup.dialinginfo.interfaces[0])
4543 add_trace("interface", "to", "%s", param->setup.dialinginfo.interfaces);
4544 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4545 switch(param->setup.callerinfo.present) {
4546 case INFO_PRESENT_RESTRICTED:
4547 add_trace("caller id", "present", "restricted");
4549 case INFO_PRESENT_ALLOWED:
4550 add_trace("caller id", "present", "allowed");
4553 add_trace("caller id", "present", "not available");
4555 if (param->setup.callerinfo.ntype2) {
4556 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4557 switch(param->setup.callerinfo.present) {
4558 case INFO_PRESENT_RESTRICTED:
4559 add_trace("caller id2", "present", "restricted");
4561 case INFO_PRESENT_ALLOWED:
4562 add_trace("caller id2", "present", "allowed");
4565 add_trace("caller id2", "present", "not available");
4568 if (param->setup.redirinfo.id[0]) {
4569 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4570 switch(param->setup.redirinfo.present) {
4571 case INFO_PRESENT_RESTRICTED:
4572 add_trace("redir'ing", "present", "restricted");
4574 case INFO_PRESENT_ALLOWED:
4575 add_trace("redir'ing", "present", "allowed");
4578 add_trace("redir'ing", "present", "not available");
4581 if (param->setup.dialinginfo.id[0])
4582 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4583 if (param->setup.dialinginfo.keypad[0])
4584 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4585 if (param->setup.dialinginfo.display[0])
4586 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4587 if (param->setup.dialinginfo.sending_complete)
4588 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4592 case MESSAGE_OVERLAP:
4593 trace_header("SETUP ACKNOWLEDGE", dir);
4594 if (dir == DIRECTION_OUT)
4595 add_trace("to", NULL, "CH(%lu)", port_id);
4596 if (dir == DIRECTION_IN)
4597 add_trace("from", NULL, "CH(%lu)", port_id);
4601 case MESSAGE_PROCEEDING:
4602 trace_header("PROCEEDING", dir);
4603 if (dir == DIRECTION_OUT)
4604 add_trace("to", NULL, "CH(%lu)", port_id);
4605 if (dir == DIRECTION_IN)
4606 add_trace("from", NULL, "CH(%lu)", port_id);
4610 case MESSAGE_ALERTING:
4611 trace_header("ALERTING", dir);
4612 if (dir == DIRECTION_OUT)
4613 add_trace("to", NULL, "CH(%lu)", port_id);
4614 if (dir == DIRECTION_IN)
4615 add_trace("from", NULL, "CH(%lu)", port_id);
4619 case MESSAGE_CONNECT:
4620 trace_header("CONNECT", dir);
4621 if (dir == DIRECTION_OUT)
4622 add_trace("to", NULL, "CH(%lu)", port_id);
4623 if (dir == DIRECTION_IN)
4624 add_trace("from", NULL, "CH(%lu)", port_id);
4625 if (param->connectinfo.extension[0])
4626 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4627 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4628 switch(param->connectinfo.present) {
4629 case INFO_PRESENT_RESTRICTED:
4630 add_trace("connect id", "present", "restricted");
4632 case INFO_PRESENT_ALLOWED:
4633 add_trace("connect id", "present", "allowed");
4636 add_trace("connect id", "present", "not available");
4638 if (param->connectinfo.display[0])
4639 add_trace("display", NULL, "%s", param->connectinfo.display);
4643 case MESSAGE_DISCONNECT:
4644 case MESSAGE_RELEASE:
4645 if (message_type == MESSAGE_DISCONNECT)
4646 trace_header("DISCONNECT", dir);
4648 trace_header("RELEASE", dir);
4649 if (dir == DIRECTION_OUT)
4650 add_trace("to", NULL, "CH(%lu)", port_id);
4651 if (dir == DIRECTION_IN)
4652 add_trace("from", NULL, "CH(%lu)", port_id);
4653 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4654 switch(param->disconnectinfo.location) {
4656 add_trace("cause", "location", "0-User");
4658 case LOCATION_PRIVATE_LOCAL:
4659 add_trace("cause", "location", "1-Local-PBX");
4661 case LOCATION_PUBLIC_LOCAL:
4662 add_trace("cause", "location", "2-Local-Exchange");
4664 case LOCATION_TRANSIT:
4665 add_trace("cause", "location", "3-Transit");
4667 case LOCATION_PUBLIC_REMOTE:
4668 add_trace("cause", "location", "4-Remote-Exchange");
4670 case LOCATION_PRIVATE_REMOTE:
4671 add_trace("cause", "location", "5-Remote-PBX");
4673 case LOCATION_INTERNATIONAL:
4674 add_trace("cause", "location", "7-International-Exchange");
4676 case LOCATION_BEYOND:
4677 add_trace("cause", "location", "10-Beyond-Interworking");
4680 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4682 if (param->disconnectinfo.display[0])
4683 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4687 case MESSAGE_NOTIFY:
4688 switch(param->notifyinfo.notify) {
4693 logtext = "USER_SUSPENDED";
4696 logtext = "BEARER_SERVICE_CHANGED";
4699 logtext = "USER_RESUMED";
4702 logtext = "CONFERENCE_ESTABLISHED";
4705 logtext = "CONFERENCE_DISCONNECTED";
4708 logtext = "OTHER_PARTY_ADDED";
4711 logtext = "ISOLATED";
4714 logtext = "REATTACHED";
4717 logtext = "OTHER_PARTY_ISOLATED";
4720 logtext = "OTHER_PARTY_REATTACHED";
4723 logtext = "OTHER_PARTY_SPLIT";
4726 logtext = "OTHER_PARTY_DISCONNECTED";
4729 logtext = "CONFERENCE_FLOATING";
4732 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4735 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4738 logtext = "CALL_IS_A_WAITING_CALL";
4741 logtext = "DIVERSION_ACTIVATED";
4744 logtext = "RESERVED_CT_1";
4747 logtext = "RESERVED_CT_2";
4750 logtext = "REVERSE_CHARGING";
4753 logtext = "REMOTE_HOLD";
4756 logtext = "REMOTE_RETRIEVAL";
4759 logtext = "CALL_IS_DIVERTING";
4762 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4766 trace_header("NOTIFY", dir);
4767 if (dir == DIRECTION_OUT)
4768 add_trace("to", NULL, "CH(%lu)", port_id);
4769 if (dir == DIRECTION_IN)
4770 add_trace("from", NULL, "CH(%lu)", port_id);
4771 if (param->notifyinfo.notify)
4772 add_trace("indicator", NULL, "%s", logtext);
4773 if (param->notifyinfo.id[0]) {
4774 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4775 switch(param->notifyinfo.present) {
4776 case INFO_PRESENT_RESTRICTED:
4777 add_trace("redir'on", "present", "restricted");
4779 case INFO_PRESENT_ALLOWED:
4780 add_trace("redir'on", "present", "allowed");
4783 add_trace("redir'on", "present", "not available");
4786 if (param->notifyinfo.display[0])
4787 add_trace("display", NULL, "%s", param->notifyinfo.display);
4791 case MESSAGE_PROGRESS:
4792 switch(param->progressinfo.progress) {
4794 logtext = "Call is not end to end ISDN";
4797 logtext = "Destination address is non-ISDN";
4800 logtext = "Origination address is non-ISDN";
4803 logtext = "Call has returned to the ISDN";
4806 logtext = "In-band info or pattern available";
4809 SPRINT(buffer, "%d", param->progressinfo.progress);
4813 trace_header("PROGRESS", dir);
4814 if (dir == DIRECTION_OUT)
4815 add_trace("to", NULL, "CH(%lu)", port_id);
4816 if (dir == DIRECTION_IN)
4817 add_trace("from", NULL, "CH(%lu)", port_id);
4818 add_trace("indicator", NULL, "%s", logtext);
4819 switch(param->progressinfo.location) {
4821 add_trace("cause", "location", "0-User");
4823 case LOCATION_PRIVATE_LOCAL:
4824 add_trace("cause", "location", "1-Local-PBX");
4826 case LOCATION_PUBLIC_LOCAL:
4827 add_trace("cause", "location", "2-Local-Exchange");
4829 case LOCATION_TRANSIT:
4830 add_trace("cause", "location", "3-Transit");
4832 case LOCATION_PUBLIC_REMOTE:
4833 add_trace("cause", "location", "4-Remote-Exchange");
4835 case LOCATION_PRIVATE_REMOTE:
4836 add_trace("cause", "location", "5-Remote-PBX");
4838 case LOCATION_INTERNATIONAL:
4839 add_trace("cause", "location", "7-International-Exchange");
4841 case LOCATION_BEYOND:
4842 add_trace("cause", "location", "10-Beyond-Interworking");
4845 add_trace("cause", "location", "%d", param->progressinfo.location);
4850 case MESSAGE_INFORMATION:
4851 trace_header("INFORMATION", dir);
4852 if (dir == DIRECTION_OUT)
4853 add_trace("to", NULL, "CH(%lu)", port_id);
4854 if (dir == DIRECTION_IN)
4855 add_trace("from", NULL, "CH(%lu)", port_id);
4856 if (param->information.id[0])
4857 add_trace("dialing", NULL, "%s", param->information.id);
4858 if (param->information.display[0])
4859 add_trace("display", NULL, "%s", param->information.display);
4860 if (param->information.sending_complete)
4861 add_trace("complete", NULL, "true", param->information.sending_complete);
4865 case MESSAGE_FACILITY:
4866 trace_header("FACILITY", dir);
4867 if (dir == DIRECTION_OUT)
4868 add_trace("to", NULL, "CH(%lu)", port_id);
4869 if (dir == DIRECTION_IN)
4870 add_trace("from", NULL, "CH(%lu)", port_id);
4875 trace_header("TONE", dir);
4876 if (dir == DIRECTION_OUT)
4877 add_trace("to", NULL, "CH(%lu)", port_id);
4878 if (dir == DIRECTION_IN)
4879 add_trace("from", NULL, "CH(%lu)", port_id);
4880 if (param->tone.name[0]) {
4881 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4882 add_trace("name", NULL, "%s", param->tone.name);
4884 add_trace("off", NULL, NULL);
4888 case MESSAGE_SUSPEND:
4889 case MESSAGE_RESUME:
4890 if (message_type == MESSAGE_SUSPEND)
4891 trace_header("SUSPEND", dir);
4893 trace_header("RESUME", dir);
4894 if (dir == DIRECTION_OUT)
4895 add_trace("to", NULL, "CH(%lu)", port_id);
4896 if (dir == DIRECTION_IN)
4897 add_trace("from", NULL, "CH(%lu)", port_id);
4898 if (param->parkinfo.len)
4899 add_trace("length", NULL, "%d", param->parkinfo.len);
4904 case MESSAGE_BCHANNEL:
4905 trace_header("BCHANNEL", dir);
4906 switch(param->bchannel.type) {
4907 case BCHANNEL_REQUEST:
4908 add_trace("type", NULL, "request");
4910 case BCHANNEL_ASSIGN:
4911 add_trace("type", NULL, "assign");
4913 case BCHANNEL_ASSIGN_ACK:
4914 add_trace("type", NULL, "assign_ack");
4916 case BCHANNEL_REMOVE:
4917 add_trace("type", NULL, "remove");
4919 case BCHANNEL_REMOVE_ACK:
4920 add_trace("type", NULL, "remove_ack");
4923 if (param->bchannel.addr)
4924 add_trace("address", NULL, "%x", param->bchannel.addr);
4930 if (param->threepty.begin)
4931 trace_header("Begin3PTY", dir);
4932 if (param->threepty.end)
4933 trace_header("End3PTY", dir);
4934 if (param->threepty.invoke)
4935 add_trace("action", NULL, "invoke");
4936 if (param->threepty.result)
4937 add_trace("action", NULL, "result");
4938 if (param->threepty.error)
4939 add_trace("action", NULL, "error");
4940 add_trace("invoke-id", NULL, "%d", param->threepty.invoke_id);
4944 case MESSAGE_TRANSFER:
4945 trace_header("TRANSFER", dir);
4946 if (param->transfer.invoke)
4947 add_trace("action", NULL, "invoke");
4948 if (param->transfer.result)
4949 add_trace("action", NULL, "result");
4950 if (param->transfer.error)
4951 add_trace("action", NULL, "error");
4952 add_trace("invoke-id", NULL, "%d", param->transfer.invoke_id);
4956 case MESSAGE_DISABLE_DEJITTER:
4957 trace_header("DISBALE_DEJITTER", dir);
4959 add_trace("queue", NULL, "%d", param->queue);
4963 case MESSAGE_DOV_INDICATION:
4964 case MESSAGE_DOV_REQUEST:
4965 trace_header("Data-Over-Voice", dir);
4966 if (dir == DIRECTION_OUT)
4967 add_trace("to", NULL, "CH(%lu)", port_id);
4968 if (dir == DIRECTION_IN)
4969 add_trace("from", NULL, "CH(%lu)", port_id);
4971 char dov_str[param->dov.length + 1];
4972 memcpy(dov_str, param->dov.data, param->dov.length);
4973 dov_str[param->dov.length] = '\0';
4974 add_trace("string", NULL, "%s", dov_str);
4976 add_trace("type", NULL, "%d", param->dov.type);
4981 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4985 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display, const struct param_transfer *transfer)
4987 struct lcr_msg *message;
4991 if (!portlist->port_id)
4994 if (!e_connectedmode) {
4995 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4996 message->param.disconnectinfo.cause = cause;
4997 message->param.disconnectinfo.location = location;
4999 SCPY(message->param.disconnectinfo.display, display);
5001 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
5003 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
5005 SCPY(message->param.notifyinfo.display, display);
5007 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
5010 memcpy(&message->param.disconnectinfo.transfer, transfer, sizeof(struct param_transfer));
5012 message_put(message);
5013 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
5016 void EndpointAppPBX::dov_msg_write(union parameter *param, int sent)
5021 int __attribute__((__unused__)) rc;
5023 /* no write, if no log file given */
5024 if (!e_ext.dov_log[0])
5027 fp = fopen(e_ext.dov_log, "a");
5029 PERROR("EPOINT(%d) failed to open Data-Over-Voice log file '%s'\n", ea_endpoint->ep_serial, e_ext.dov_log);
5034 tm = localtime(&ti);
5035 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);
5039 fprintf(fp, "sent [%s] ", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international));
5041 fprintf(fp, "received [%s] ", e_dialinginfo.id);
5044 rc = fwrite(param->dov.data, param->dov.length, 1, fp);