1 /*****************************************************************************\
3 ** Linux Call Router **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** The EndpointAppPBX implements PBX4Linux **
10 \*****************************************************************************/
15 class EndpointAppPBX *apppbx_first = NULL;
18 * EndpointAppPBX constructor
20 EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin)
22 class EndpointAppPBX **apppointer;
24 /* add application to chain */
26 apppointer = &apppbx_first;
28 apppointer = &((*apppointer)->next);
32 memset(&e_ext, 0, sizeof(struct extension));
33 // *************** NOTE: also change value in read_extension() **************
34 e_ext.rights = 4; /* international */
35 e_ext.rx_gain = e_ext.tx_gain = 0;
36 e_state = EPOINT_STATE_IDLE;
37 e_ext.number[0] = '\0';
38 e_extension_interface[0] = '\0';
39 memset(&e_callerinfo, 0, sizeof(struct caller_info));
40 memset(&e_dialinginfo, 0, sizeof(struct dialing_info));
41 memset(&e_connectinfo, 0, sizeof(struct connect_info));
42 memset(&e_redirinfo, 0, sizeof(struct redir_info));
43 memset(&e_capainfo, 0, sizeof(struct capa_info));
46 e_ruleset = ruleset_main;
48 e_rule = e_ruleset->rule_first;
53 e_match_to_action = NULL;
55 e_extdialing = e_dialinginfo.id;
59 // e_join_tone[0] = e_hold_tone[0] = '\0';
60 e_join_pattern /*= e_hold_pattern*/ = 0;
63 e_adminid = 0; // will be set, if call was initiated via admin socket
68 e_cbdialing[0] = '\0';
71 memset(&e_callbackinfo, 0, sizeof(struct caller_info));
79 e_password_timeout = 0;
80 e_multipoint_cause = 0;
81 e_multipoint_location = 0;
82 e_dialing_queue[0] = '\0';
84 e_crypt_state = CM_ST_NULL;
85 e_crypt_keyengine_busy = 0;
86 e_crypt_info[0] = '\0';
89 e_tx_state = NOTIFY_STATE_ACTIVE;
90 e_rx_state = NOTIFY_STATE_ACTIVE;
91 e_join_cause = e_join_location = 0;
92 /*********************************
93 *********************************
94 ********* ATTENTION *************
95 *********************************
96 *********************************/
97 /* if you add new values, that must be initialized, also check if they must
98 * be initialized when doing callback
104 * EpointAppPBX destructor
106 EndpointAppPBX::~EndpointAppPBX(void)
108 class EndpointAppPBX *temp, **tempp;
112 tempp = &apppbx_first;
121 FATAL("Endpoint not in endpoint's list.\n");
128 * trace header for application
130 void EndpointAppPBX::trace_header(const char *name, int direction)
134 char msgtext[sizeof(_trace.name)];
138 /* init trace with given values */
141 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
145 ea_endpoint->ep_serial,
152 /* set new endpoint state
154 void EndpointAppPBX::new_state(int state)
157 if (e_state != state) {
158 trace_header("NEW STATE", DIRECTION_NONE);
159 add_trace("state", "old", "%s", state_name[e_state]);
160 add_trace("state", "new", "%s", state_name[state]);
168 /* release join and port (as specified)
170 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause)
172 struct port_list *portlist;
173 struct lcr_msg *message;
176 /* message to test call */
177 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
179 /* if a release is pending */
180 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
182 if (ea_endpoint->ep_join_id) {
183 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
184 message->param.disconnectinfo.cause = joincause;
185 message->param.disconnectinfo.location = joinlocation;
186 message_put(message);
187 ea_endpoint->ep_join_id = 0;
191 if (release != RELEASE_PORT_JOINONLY) {
193 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
198 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
199 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
200 while((portlist = ea_endpoint->ep_portlist)) {
201 if (portlist->port_id) {
202 SPRINT(cause, "cause_%02x", portcause);
203 set_tone(portlist, cause);
204 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
205 message->param.disconnectinfo.cause = portcause;
206 message->param.disconnectinfo.location = portlocation;
207 message_put(message);
208 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
210 ea_endpoint->free_portlist(portlist);
213 /* if callback is enabled, call back with the given caller id */
215 /* reset some stuff */
216 new_state(EPOINT_STATE_IDLE);
217 memset(&e_connectinfo, 0, sizeof(struct connect_info));
218 memset(&e_redirinfo, 0, sizeof(struct redir_info));
219 e_start = e_stop = 0;
220 e_ruleset = ruleset_main;
222 e_rule = e_ruleset->rule_first;
224 e_action_timeout = 0;
226 e_match_to_action = NULL;
228 e_extdialing = e_dialinginfo.id;
236 e_multipoint_cause = 0;
237 e_multipoint_location = 0;
238 e_dialing_queue[0] = '\0';
240 e_crypt_state = CM_ST_NULL;
241 e_crypt_keyengine_busy = 0;
242 e_crypt_info[0] = '\0';
246 e_tx_state = NOTIFY_STATE_ACTIVE;
247 e_rx_state = NOTIFY_STATE_ACTIVE;
248 e_join_cause = e_join_location = 0;
250 /* the caller info of the callback user */
251 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
252 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
253 /* create dialing by callerinfo */
254 if (e_ext.number[0] && e_extension_interface[0]) {
255 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
256 /* create callback to the current terminal */
257 SCPY(e_dialinginfo.id, e_ext.number);
258 SCPY(e_dialinginfo.interfaces, e_extension_interface);
259 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
260 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
263 SCPY(e_dialinginfo.id, e_cbto);
265 /* numberrize caller id and use it to dial to the callback */
266 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
268 e_dialinginfo.itype = INFO_ITYPE_ISDN;
269 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
270 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
275 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
276 ea_endpoint->ep_use--; /* when e_lock is 0, the endpoint will be deleted */
282 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
283 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
285 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");
287 /* caller id is not restricted, so we do nothing */
288 if (*present != INFO_PRESENT_RESTRICTED)
291 /* only extensions are restricted */
295 /* if we enabled anonymouse ignore */
296 if (ext->anon_ignore)
299 /* else we remove the caller id */
303 *ntype = INFO_NTYPE_UNKNOWN;
305 // *screen = INFO_SCREEN_USER;
306 // maybe we should not make voip address anonymous
309 // maybe it's no fraud to present extension id
311 // extension[0] = '\0';
316 /* used display message to display callerid as available */
317 char *EndpointAppPBX::apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name)
319 static char display[81];
322 const char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
324 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");
333 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
335 /* internal extension's caller id */
336 if (extension[0] && e_ext.display_int) {
338 SCAT(display, extension);
341 if (itype == INFO_ITYPE_VBOX)
342 SCAT(display, "(vbox)");
344 SCAT(display, "(int)");
347 /* external caller id */
348 if (!extension[0] && e_ext.display_ext) {
351 if (present == INFO_PRESENT_RESTRICTED)
352 SCAT(display, "anonymous");
354 SCAT(display, "unknown");
361 /* display if callerid is anonymouse but available due anon-ignore */
362 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED) {
364 SCAT(display, "unknown");
367 SCAT(display, " anon");
370 /* display if callerid is anonymouse but available due anon-ignore */
371 if (e_ext.display_fake && screen==INFO_SCREEN_USER && ntype!=INFO_NTYPE_NOTPRESENT) {
374 if (present == INFO_PRESENT_RESTRICTED)
375 SCAT(display, "anonymous");
377 SCAT(display, "unknown");
382 SCAT(display, " fake");
386 if (name[0] && e_ext.display_name) {
387 if (!display[0] && cid[0])
398 * uses the current state to notify activity
400 void EndpointAppPBX::notify_active(void)
402 struct port_list *portlist = ea_endpoint->ep_portlist;
403 struct lcr_msg *message;
407 case NOTIFY_STATE_ACTIVE:
408 /* we are already active, so we don't do anything */
411 case NOTIFY_STATE_SUSPEND:
412 notify = INFO_NOTIFY_USER_RESUMED;
414 set_tone(portlist, NULL);
415 portlist = portlist->next;
417 portlist = ea_endpoint->ep_portlist;
420 case NOTIFY_STATE_HOLD:
421 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
423 set_tone(portlist, NULL);
424 portlist = portlist->next;
426 portlist = ea_endpoint->ep_portlist;
429 case NOTIFY_STATE_CONFERENCE:
430 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
432 set_tone(portlist, NULL);
433 portlist = portlist->next;
435 portlist = ea_endpoint->ep_portlist;
439 PERROR("unknown e_tx_state = %d\n", e_tx_state);
444 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
445 message->param.notifyinfo.notify = notify;
446 message_put(message);
447 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
448 portlist = portlist->next;
454 * keypad functions during call. one example to use this is to put a call on hold or start a conference
456 void EndpointAppPBX::keypad_function(char digit)
459 /* we must be in a call, in order to send messages to the call */
460 if (e_ext.number[0] == '\0') {
461 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
466 /* join conference */
468 if (ea_endpoint->ep_join_id == 0) {
469 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
472 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
478 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
482 /* crypt key-exchange */
484 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
490 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
495 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
500 /* set tone pattern for port */
501 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
503 struct lcr_msg *message;
508 /* store for suspended processes */
512 if (e_join_pattern /* pattern are provided */
513 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
514 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
515 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
516 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
517 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
518 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
519 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
520 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
521 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
522 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
523 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
524 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
529 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
530 SCPY(message->param.tone.dir, e_ext.tones_dir);
531 SCPY(message->param.tone.name, tone);
532 message_put(message);
533 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
535 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
542 * hunts an mISDNport that is available for an outgoing call
543 * if no ifname was given, any interface that is not an extension
546 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
548 struct interface *interface;
549 struct interface_port *ifport, *ifport_start;
550 struct select_channel *selchannel;
551 struct mISDNport *mISDNport;
554 interface = interface_first;
556 /* first find the given interface or, if not given, one with no extension */
561 /* check for given interface */
563 if (!strcasecmp(interface->name, ifname)) {
564 /* found explicit interface */
565 trace_header("CHANNEL SELECTION (found interface)", DIRECTION_NONE);
566 add_trace("interface", NULL, "%s", ifname);
572 if (!interface->extension) {
573 /* found non extension */
574 trace_header("CHANNEL SELECTION (found non extension interface)", DIRECTION_NONE);
575 add_trace("interface", NULL, "%s", interface->name);
581 interface = interface->next;
585 /* see if interface has ports */
586 if (!interface->ifport) {
588 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
589 add_trace("interface", NULL, "%s", interface->name);
591 interface = interface->next;
595 /* select port by algorithm */
596 ifport_start = interface->ifport;
598 if (interface->hunt == HUNT_ROUNDROBIN) {
599 while(ifport_start->next && index<interface->hunt_next) {
600 ifport_start = ifport_start->next;
603 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
604 add_trace("port", NULL, "%d", ifport_start->portnum);
605 add_trace("position", NULL, "%d", index);
610 ifport = ifport_start;
613 /* see if port is available */
614 if (!ifport->mISDNport) {
615 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
616 add_trace("port", NULL, "%d", ifport->portnum);
617 add_trace("position", NULL, "%d", index);
621 mISDNport = ifport->mISDNport;
623 /* see if port is administratively blocked */
625 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
626 add_trace("port", NULL, "%d", ifport->portnum);
627 add_trace("position", NULL, "%d", index);
632 /* see if link is up on PTP*/
633 if (mISDNport->l2hold && mISDNport->l2link<1) {
634 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
635 add_trace("port", NULL, "%d", ifport->portnum);
636 add_trace("position", NULL, "%d", index);
641 /* check for channel form selection list */
643 selchannel = ifport->out_channel;
645 switch(selchannel->channel) {
646 case CHANNEL_FREE: /* free channel */
647 if (mISDNport->b_reserved >= mISDNport->b_num)
648 break; /* all channel in use or reserverd */
651 while(i < mISDNport->b_num) {
652 if (mISDNport->b_port[i] == NULL) {
653 *channel = i+1+(i>=15);
654 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
655 add_trace("port", NULL, "%d", ifport->portnum);
656 add_trace("position", NULL, "%d", index);
657 add_trace("channel", NULL, "%d", *channel);
665 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
666 add_trace("port", NULL, "%d", ifport->portnum);
667 add_trace("position", NULL, "%d", index);
671 case CHANNEL_ANY: /* don't ask for channel */
672 if (mISDNport->b_reserved >= mISDNport->b_num) {
673 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
674 add_trace("port", NULL, "%d", ifport->portnum);
675 add_trace("position", NULL, "%d", index);
676 add_trace("total", NULL, "%d", mISDNport->b_num);
677 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
679 break; /* all channel in use or reserverd */
681 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
682 add_trace("port", NULL, "%d", ifport->portnum);
683 add_trace("position", NULL, "%d", index);
685 *channel = CHANNEL_ANY;
688 case CHANNEL_NO: /* call waiting */
689 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
690 add_trace("port", NULL, "%d", ifport->portnum);
691 add_trace("position", NULL, "%d", index);
693 *channel = CHANNEL_NO;
697 if (selchannel->channel<1 || selchannel->channel==16) {
698 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
699 add_trace("port", NULL, "%d", ifport->portnum);
700 add_trace("position", NULL, "%d", index);
701 add_trace("channel", NULL, "%d", selchannel->channel);
703 break; /* invalid channels */
705 i = selchannel->channel-1-(selchannel->channel>=17);
706 if (i >= mISDNport->b_num) {
707 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
708 add_trace("port", NULL, "%d", ifport->portnum);
709 add_trace("position", NULL, "%d", index);
710 add_trace("channel", NULL, "%d", selchannel->channel);
711 add_trace("channels", NULL, "%d", mISDNport->b_num);
713 break; /* channel not in port */
715 if (mISDNport->b_port[i] == NULL) {
716 *channel = selchannel->channel;
717 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
718 add_trace("port", NULL, "%d", ifport->portnum);
719 add_trace("position", NULL, "%d", index);
720 add_trace("channel", NULL, "%d", *channel);
727 break; /* found channel */
728 selchannel = selchannel->next;
731 /* if channel was found, return mISDNport and channel */
733 /* setting next port to start next time */
734 if (interface->hunt == HUNT_ROUNDROBIN) {
738 interface->hunt_next = index;
744 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
745 add_trace("port", NULL, "%d", ifport->portnum);
746 add_trace("position", NULL, "%d", index);
750 /* go next port, until all ports are checked */
752 ifport = ifport->next;
755 ifport = interface->ifport;
757 if (ifport != ifport_start)
761 interface = interface->next;
765 return(NULL); /* no port found */
768 /* outgoing setup to port(s)
769 * ports will be created and a setup is sent if everything is ok. otherwhise
770 * the endpoint is destroyed.
772 void EndpointAppPBX::out_setup(void)
774 struct dialing_info dialinginfo;
776 struct port_list *portlist;
777 struct lcr_msg *message;
779 int cause = CAUSE_RESSOURCEUNAVAIL;
782 struct mISDNport *mISDNport;
785 class EndpointAppPBX *atemp;
786 // char allowed_ports[256];
788 char ifname[sizeof(e_ext.interfaces)],
790 struct port_settings port_settings;
793 int mode = B_MODE_TRANSPARENT;
795 /* set bchannel mode */
796 mode = e_capainfo.source_mode;
798 /* create settings for creating port */
799 memset(&port_settings, 0, sizeof(port_settings));
801 SCPY(port_settings.tones_dir, e_ext.tones_dir);
803 SCPY(port_settings.tones_dir, options.tones_dir);
804 port_settings.no_seconds = e_ext.no_seconds;
806 /* 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 */
808 /* check what dialinginfo.itype we got */
809 switch(e_dialinginfo.itype) {
810 /* *********************** call to extension or vbox */
811 case INFO_ITYPE_ISDN_EXTENSION:
812 /* check if we deny incoming calls when we use an extension */
813 if (e_ext.noknocking) {
814 atemp = apppbx_first;
817 if (!strcmp(atemp->e_ext.number, e_ext.number))
822 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
823 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYSPE_ join, port */
824 return; /* must exit here */
827 /* FALL THROUGH !!!! */
828 case INFO_ITYPE_VBOX:
829 /* get dialed extension's info */
830 // SCPY(exten, e_dialinginfo.id);
831 // if (strchr(exten, ','))
832 // *strchr(exten, ',') = '\0';
833 // if (!read_extension(&e_ext, exten))
834 if (!read_extension(&e_ext, e_dialinginfo.id)) {
835 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
836 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
837 return; /* must exit here */
840 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
841 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
846 /* string from unconditional call forward (cfu) */
849 /* present to forwarded party */
850 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
851 e_callerinfo.present = INFO_PRESENT_ALLOWED;
853 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
857 /* string from busy call forward (cfb) */
860 class EndpointAppPBX *checkapp = apppbx_first;
862 if (checkapp != this) { /* any other endpoint except our own */
863 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
864 /* present to forwarded party */
865 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
866 e_callerinfo.present = INFO_PRESENT_ALLOWED;
868 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
872 checkapp = checkapp->next;
876 /* string from no-response call forward (cfnr) */
879 /* when cfnr is done, out_setup() will setup the call */
881 /* present to forwarded party */
882 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
883 e_callerinfo.present = INFO_PRESENT_ALLOWED;
887 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
888 e_cfnr_release = now + e_ext.cfnr_delay;
889 e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */
890 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);
894 /* call to all internal interfaces */
895 p = e_ext.interfaces;
896 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
899 while(*p!=',' && *p!='\0')
904 /* found interface */
905 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
906 /* hunt for mISDNport and create Port */
907 mISDNport = hunt_port(ifname, &channel);
909 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
910 add_trace("interface", NULL, "%s", ifname);
914 /* creating INTERNAL port */
915 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
917 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
920 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
925 FATAL("No memory for Port instance\n");
926 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
927 memset(&dialinginfo, 0, sizeof(dialinginfo));
928 SCPY(dialinginfo.id, e_dialinginfo.id);
929 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
930 dialinginfo.ntype = e_dialinginfo.ntype;
931 /* create port_list relation */
932 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
934 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
936 goto check_anycall_intern;
939 if (e_callerinfo.id[0] && e_ext.display_name) {
940 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
942 SCPY(e_callerinfo.name, dirname);
944 // dss1 = (class Pdss1 *)port;
946 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
947 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
948 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
949 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
950 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
951 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
952 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
953 //terminal if (e_dialinginfo.id)
954 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
955 /* handle restricted caller ids */
956 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);
957 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);
958 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);
959 /* display callerid if desired for extension */
960 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));
961 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
962 /* use cnip, if enabld */
963 // if (!e_ext.centrex)
964 // message->param.setup.callerinfo.name[0] = '\0';
965 /* screen clip if prefix is required */
966 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
967 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
968 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
969 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
971 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
972 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
973 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
974 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
976 /* use internal caller id */
977 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
978 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
979 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
980 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
982 message_put(message);
983 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
987 /* string from parallel call forward (cfp) */
990 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
991 e_callerinfo.present = INFO_PRESENT_ALLOWED;
992 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
996 vbox_only: /* entry point for answering machine only */
997 cfu_only: /* entry point for cfu */
998 cfb_only: /* entry point for cfb */
999 cfnr_only: /* entry point for cfnr */
1000 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1004 /* only if vbox should be dialed, and terminal is given */
1005 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1006 /* go to the end of p */
1009 /* answering vbox call */
1010 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1012 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1013 FATAL("No memory for VBOX Port instance\n");
1014 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1015 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1018 while(*p!=',' && *p!='\0')
1023 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1024 /* hunt for mISDNport and create Port */
1025 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1027 /* creating EXTERNAL port*/
1028 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1029 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1031 FATAL("No memory for Port instance\n");
1032 earlyb = mISDNport->earlyb;
1035 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1036 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1041 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1042 goto check_anycall_intern;
1044 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1045 memset(&dialinginfo, 0, sizeof(dialinginfo));
1046 SCPY(dialinginfo.id, cfp);
1047 dialinginfo.itype = INFO_ITYPE_ISDN;
1048 dialinginfo.ntype = e_dialinginfo.ntype;
1049 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1051 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1053 goto check_anycall_intern;
1055 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1056 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1057 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1058 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1059 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1060 /* if clip is hidden */
1061 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1062 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1063 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1064 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1065 message->param.setup.callerinfo.present = e_ext.callerid_present;
1066 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1068 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1069 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1070 //terminal if (e_dialinginfo.id)
1071 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1072 /* handle restricted caller ids */
1073 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);
1074 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);
1075 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);
1076 /* display callerid if desired for extension */
1077 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));
1078 message_put(message);
1079 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1083 check_anycall_intern:
1084 /* now we have all ports created */
1086 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1088 if (!ea_endpoint->ep_join_id)
1090 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1091 return; /* must exit here */
1095 /* *********************** external call */
1097 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id);
1098 /* call to extenal interfaces */
1099 p = e_dialinginfo.id;
1102 while(*p!=',' && *p!='\0')
1103 SCCAT(number, *p++);
1107 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1108 /* hunt for mISDNport and create Port */
1109 /* hunt for mISDNport and create Port */
1110 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1112 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1113 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1115 goto check_anycall_extern;
1117 /* creating EXTERNAL port*/
1118 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1119 if (!mISDNport->gsm)
1120 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1123 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1128 FATAL("No memory for Port instance\n");
1129 earlyb = mISDNport->earlyb;
1130 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1131 memset(&dialinginfo, 0, sizeof(dialinginfo));
1132 SCPY(dialinginfo.id, number);
1133 dialinginfo.itype = INFO_ITYPE_ISDN;
1134 dialinginfo.ntype = e_dialinginfo.ntype;
1135 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1137 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1139 goto check_anycall_extern;
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 SCPY(message->param.setup.dialinginfo.id, number);
1145 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1146 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1147 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_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);
1162 check_anycall_extern:
1163 /* now we have all ports created */
1165 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1167 if (!ea_endpoint->ep_join_id)
1169 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1170 return; /* must exit here */
1178 /* handler for endpoint
1182 int EndpointAppPBX::handler(void)
1184 if (e_crypt_state!=CM_ST_NULL) {
1188 /* process answering machine (play) handling */
1190 if (e_action->index == ACTION_VBOX_PLAY)
1193 /* process action timeout */
1194 if (e_action_timeout)
1195 if (now_d >= e_action_timeout) {
1196 if (e_state!=EPOINT_STATE_CONNECT) {
1198 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea_endpoint->ep_serial);
1199 e_multipoint_cause = 0;
1200 e_multipoint_location = 0;
1201 new_state(EPOINT_STATE_IN_OVERLAP);
1204 return(1); /* we must exit, because our endpoint might be gone */
1206 e_action_timeout = 0;
1209 /* process action timeout */
1210 if (e_match_timeout)
1211 if (now_d >= e_match_timeout) {
1213 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea_endpoint->ep_serial);
1215 return(1); /* we must exit, because our endpoint might be gone */
1220 /* process redialing (epoint redials to port) */
1222 if (now_d >= e_redial) {
1224 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea_endpoint->ep_serial);
1226 new_state(EPOINT_STATE_OUT_SETUP);
1227 /* call special setup routine */
1234 /* process powerdialing (epoint redials to epoint) */
1235 if (e_powerdialing > 0) {
1236 if (now_d >= e_powerdialing) {
1237 e_powerdialing = -1; /* leave power dialing on */
1238 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea_endpoint->ep_serial);
1241 e_ruleset = ruleset_main;
1243 e_rule = e_ruleset->rule_first;
1245 new_state(EPOINT_STATE_IN_OVERLAP);
1251 /* process call forward no response */
1252 if (e_cfnr_release) {
1253 struct port_list *portlist;
1254 struct lcr_msg *message;
1256 if (now >= e_cfnr_release) {
1257 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea_endpoint->ep_serial);
1260 /* release all ports */
1261 while((portlist = ea_endpoint->ep_portlist)) {
1262 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1263 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1264 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1265 message_put(message);
1266 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1267 ea_endpoint->free_portlist(portlist);
1270 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1271 message->param.audiopath = 0;
1272 message_put(message);
1273 /* indicate no patterns */
1274 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1275 message_put(message);
1276 /* set setup state, since we have no response from the new join */
1277 new_state(EPOINT_STATE_OUT_SETUP);
1281 if (now >= e_cfnr_call) {
1282 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea_endpoint->ep_serial, e_ext.cfnr);
1288 /* handle connection to user */
1289 if (e_state == EPOINT_STATE_IDLE) {
1290 /* epoint is idle, check callback */
1292 if (now_d >= e_callback) {
1293 e_callback = 0; /* done with callback */
1294 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea_endpoint->ep_serial);
1295 new_state(EPOINT_STATE_OUT_SETUP);
1301 /* check for password timeout */
1303 if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE) {
1304 struct port_list *portlist;
1306 if (now >= e_password_timeout) {
1307 e_ruleset = ruleset_main;
1309 e_rule = e_ruleset->rule_first;
1311 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea_endpoint->ep_serial, e_extdialing);
1312 trace_header("PASSWORD timeout", DIRECTION_NONE);
1314 e_connectedmode = 0;
1316 new_state(EPOINT_STATE_OUT_DISCONNECT);
1317 portlist = ea_endpoint->ep_portlist;
1319 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1320 set_tone(portlist, "cause_10");
1330 /* doing a hookflash */
1331 void EndpointAppPBX::hookflash(void)
1335 /* be sure that we are active */
1337 e_tx_state = NOTIFY_STATE_ACTIVE;
1339 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1341 if (ea_endpoint->ep_use > 1) {
1342 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1345 /* dialtone after pressing the hash key */
1346 process_hangup(e_join_cause, e_join_location);
1347 e_multipoint_cause = 0;
1348 e_multipoint_location = 0;
1349 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1351 port->set_echotest(0);
1353 if (ea_endpoint->ep_join_id) {
1354 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1356 e_ruleset = ruleset_main;
1358 e_rule = e_ruleset->rule_first;
1360 new_state(EPOINT_STATE_IN_OVERLAP);
1361 e_connectedmode = 1;
1362 SCPY(e_dialinginfo.id, e_ext.prefix);
1363 e_extdialing = e_dialinginfo.id;
1365 if (e_dialinginfo.id[0]) {
1366 set_tone(ea_endpoint->ep_portlist, "dialing");
1369 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 */
1385 struct interface *interface;
1387 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1389 portlist->port_type = param->setup.port_type;
1390 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1391 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1392 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1393 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1394 // e_dtmf = param->setup.dtmf;
1395 /* screen incoming caller id */
1396 interface = interface_first;
1398 if (!strcmp(e_callerinfo.interface, interface->name)) {
1401 interface = interface->next;
1404 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1405 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1408 /* process extension */
1409 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1410 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1411 /* port makes call from extension */
1412 SCPY(e_callerinfo.extension, e_callerinfo.id);
1413 SCPY(e_ext.number, e_callerinfo.extension);
1414 SCPY(e_extension_interface, e_callerinfo.interface);
1416 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1419 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1420 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1422 /* get extension's info about caller */
1423 if (!read_extension(&e_ext, e_ext.number)) {
1424 /* extension doesn't exist */
1425 trace_header("EXTENSION (not created)", DIRECTION_IN);
1426 add_trace("extension", NULL, "%s", e_ext.number);
1428 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1429 new_state(EPOINT_STATE_OUT_DISCONNECT);
1430 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1431 e_ext.number[0] = '\0'; /* no terminal */
1436 /* put prefix (next) in front of e_dialinginfo.id */
1437 if (e_ext.next[0]) {
1438 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1439 SCPY(e_dialinginfo.id, buffer);
1440 e_ext.next[0] = '\0';
1442 } else if (e_ext.prefix[0]) {
1443 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1444 SCPY(e_dialinginfo.id, buffer);
1447 /* screen caller id by extension's config */
1448 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1450 SCPY(e_callerinfo.name, e_ext.name);
1451 /* use caller id (or if exist: id_next_call) for this call */
1452 if (e_ext.id_next_call_present >= 0) {
1453 SCPY(e_callerinfo.id, e_ext.id_next_call);
1454 /* if we restrict the pesentation */
1455 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1456 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1457 else e_callerinfo.present = e_ext.id_next_call_present;
1458 e_callerinfo.ntype = e_ext.id_next_call_type;
1459 e_ext.id_next_call_present = -1;
1462 SCPY(e_callerinfo.id, e_ext.callerid);
1463 /* if we restrict the pesentation */
1464 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1465 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1466 else e_callerinfo.present = e_ext.callerid_present;
1467 e_callerinfo.ntype = e_ext.callerid_type;
1469 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1471 /* extension is written */
1473 write_extension(&e_ext, e_ext.number);
1475 /* set volume of rx and tx */
1476 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1477 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1478 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1479 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1480 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1481 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1482 message_put(message);
1485 /* start recording if enabled */
1486 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1487 /* check if we are a terminal */
1488 if (e_ext.number[0] == '\0')
1489 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1491 port = find_port_id(portlist->port_id);
1493 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1497 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1498 /* no terminal identification */
1499 e_ext.number[0] = '\0';
1500 e_extension_interface[0] = '\0';
1501 memset(&e_ext, 0, sizeof(e_ext));
1502 e_ext.rights = 4; /* right to dial internat */
1506 e_ruleset = ruleset_main;
1508 e_rule = e_ruleset->rule_first;
1510 e_extdialing = e_dialinginfo.id;
1511 new_state(EPOINT_STATE_IN_SETUP);
1512 if (e_dialinginfo.id[0]) {
1513 set_tone(portlist, "dialing");
1515 if (e_ext.number[0])
1516 set_tone(portlist, "dialpbx");
1518 set_tone(portlist, "dialtone");
1521 if (e_state == EPOINT_STATE_IN_SETUP) {
1522 /* request MORE info, if not already at higher state */
1523 new_state(EPOINT_STATE_IN_OVERLAP);
1524 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1525 message_put(message);
1526 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1530 /* port MESSAGE_INFORMATION */
1531 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1533 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1535 /* ignore information message without digit information */
1536 if (!param->information.id[0])
1541 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1543 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1548 /* if vbox_play is done, the information are just used as they come */
1550 if (e_action->index == ACTION_VBOX_PLAY) {
1551 /* concat dialing string */
1552 SCAT(e_dialinginfo.id, param->information.id);
1557 /* keypad when disconnect but in connected mode */
1558 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1559 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1560 /* processing keypad function */
1561 if (param->information.id[0] == '0') {
1567 /* keypad when connected */
1568 if (e_state == EPOINT_STATE_CONNECT) {
1569 if (e_ext.keypad || e_enablekeypad) {
1570 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1571 /* processing keypad function */
1572 if (param->information.id[0] == '0') {
1575 if (param->information.id[0])
1576 keypad_function(param->information.id[0]);
1578 if (e_ext.number[0])
1579 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1581 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1586 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1587 if (e_ext.number[0])
1588 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1590 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1594 if (!param->information.id[0])
1596 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1597 set_tone(portlist, "dialing");
1600 if (e_action->index==ACTION_OUTDIAL
1601 || e_action->index==ACTION_EXTERNAL
1602 || e_action->index==ACTION_REMOTE) {
1604 set_tone(portlist, "dialing");
1605 else if (!e_extdialing[0])
1606 set_tone(portlist, "dialing");
1608 /* concat dialing string */
1609 SCAT(e_dialinginfo.id, param->information.id);
1613 /* port MESSAGE_DTMF */
1614 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1616 /* only if dtmf detection is enabled */
1618 trace_header("DTMF (disabled)", DIRECTION_IN);
1622 trace_header("DTMF", DIRECTION_IN);
1623 add_trace("digit", NULL, "%c", param->dtmf);
1627 NOTE: vbox is now handled due to overlap state
1628 /* if vbox_play is done, the dtmf digits are just used as they come */
1630 if (e_action->index == ACTION_VBOX_PLAY) {
1631 /* concat dialing string */
1632 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1633 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1634 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1637 /* continue to process *X# sequences */
1641 /* check for *X# sequence */
1642 if (e_state == EPOINT_STATE_CONNECT) {
1643 if (e_dtmf_time+3 < now) {
1644 /* the last digit was too far in the past to be a sequence */
1645 if (param->dtmf == '*')
1646 /* only start is allowed in the sequence */
1651 /* we have a sequence of digits, see what we got */
1652 if (param->dtmf == '*')
1654 else if (param->dtmf>='0' && param->dtmf<='9') {
1655 /* we need to have a star before we receive the digit of the sequence */
1656 if (e_dtmf_last == '*')
1657 e_dtmf_last = param->dtmf;
1658 } else if (param->dtmf == '#') {
1660 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1661 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1662 if (e_dtmf_last == '0') {
1666 /* processing keypad function */
1668 keypad_function(e_dtmf_last);
1674 /* set last time of dtmf */
1679 /* check for ## hookflash during dialing */
1681 if (e_action->index==ACTION_PASSWORD
1682 || e_action->index==ACTION_PASSWORD_WRITE)
1684 if (param->dtmf=='#') { /* current digit is '#' */
1685 if (e_state==EPOINT_STATE_IN_DISCONNECT
1686 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1700 /* dialing using dtmf digit */
1701 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1702 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1703 set_tone(portlist, "dialing");
1705 /* concat dialing string */
1706 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1707 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1708 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1714 /* port MESSAGE_CRYPT */
1715 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1717 /* send crypt response to cryptman */
1718 if (param->crypt.type == CR_MESSAGE_IND)
1719 cryptman_msg2man(param->crypt.data, param->crypt.len);
1721 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1724 /* port MESSAGE_OVERLAP */
1725 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1727 struct lcr_msg *message;
1729 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1731 /* signal to call tool */
1732 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1734 if (e_dialing_queue[0] && portlist) {
1735 /* send what we have not dialed yet, because we had no setup complete */
1736 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1737 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1738 SCPY(message->param.information.id, e_dialing_queue);
1739 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1740 message_put(message);
1741 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1742 e_dialing_queue[0] = '\0';
1744 /* check if pattern is available */
1745 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1746 /* indicate patterns */
1747 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1748 message_put(message);
1750 /* connect audio, if not already */
1751 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1752 message->param.audiopath = 1;
1753 message_put(message);
1755 /* indicate no patterns */
1756 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1757 message_put(message);
1759 /* disconnect audio, if not already */
1760 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1761 message->param.audiopath = 0;
1762 message_put(message);
1764 new_state(EPOINT_STATE_OUT_OVERLAP);
1765 /* if we are in a join */
1766 if (ea_endpoint->ep_join_id) {
1767 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1768 memcpy(&message->param, param, sizeof(union parameter));
1769 message_put(message);
1773 /* port MESSAGE_PROCEEDING */
1774 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1776 struct lcr_msg *message;
1778 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1780 /* signal to call tool */
1781 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1783 e_state = EPOINT_STATE_OUT_PROCEEDING;
1784 /* check if pattern is availatle */
1785 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1786 /* indicate patterns */
1787 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1788 message_put(message);
1790 /* connect audio, if not already */
1791 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1792 message->param.audiopath = 1;
1793 message_put(message);
1795 /* indicate no patterns */
1796 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1797 message_put(message);
1799 /* disconnect audio, if not already */
1800 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1801 message->param.audiopath = 0;
1802 message_put(message);
1804 /* if we are in a call */
1805 if (ea_endpoint->ep_join_id) {
1806 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1807 memcpy(&message->param, param, sizeof(union parameter));
1808 message_put(message);
1812 /* port MESSAGE_ALERTING */
1813 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1815 struct lcr_msg *message;
1817 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1819 /* signal to call tool */
1820 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1823 // set_tone(portlist, "hold");
1825 new_state(EPOINT_STATE_OUT_ALERTING);
1826 /* check if pattern is available */
1827 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1828 /* indicate patterns */
1829 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1830 message_put(message);
1832 /* connect audio, if not already */
1833 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1834 message->param.audiopath = 1;
1835 message_put(message);
1837 /* indicate no patterns */
1838 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1839 message_put(message);
1841 /* disconnect audio, if not already */
1842 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1843 message->param.audiopath = 0;
1844 message_put(message);
1846 /* if we are in a call */
1847 if (ea_endpoint->ep_join_id) {
1848 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1849 memcpy(&message->param, param, sizeof(union parameter));
1850 message_put(message);
1854 /* port MESSAGE_CONNECT */
1855 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1857 struct lcr_msg *message;
1859 unsigned int port_id = portlist->port_id;
1860 struct port_list *tportlist;
1862 struct interface *interface;
1864 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1866 /* signal to call tool */
1867 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1869 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1870 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1871 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1872 tportlist = ea_endpoint->ep_portlist;
1873 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1874 tportlist = tportlist->next;
1875 if (tportlist->port_id == port_id)
1876 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1877 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1878 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1879 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1880 message_put(message);
1881 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1882 ea_endpoint->free_portlist(tportlist);
1884 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1888 /* screen incoming connected id */
1889 interface = interface_first;
1891 if (!strcmp(e_connectinfo.interface, interface->name)) {
1894 interface = interface->next;
1897 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1899 /* screen connected name */
1901 SCPY(e_connectinfo.name, e_ext.name);
1903 /* add internal id to colp */
1904 SCPY(e_connectinfo.extension, e_ext.number);
1906 /* we store the connected port number */
1907 SCPY(e_extension_interface, e_connectinfo.interface);
1909 /* for internal and am calls, we get the extension's id */
1910 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1911 SCPY(e_connectinfo.id, e_ext.callerid);
1912 SCPY(e_connectinfo.extension, e_ext.number);
1913 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1914 e_connectinfo.ntype = e_ext.callerid_type;
1915 e_connectinfo.present = e_ext.callerid_present;
1917 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
1918 e_connectinfo.itype = INFO_ITYPE_VBOX;
1919 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1922 new_state(EPOINT_STATE_CONNECT);
1924 /* set volume of rx and tx */
1925 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1926 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1927 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1928 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1929 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1930 message_put(message);
1933 e_cfnr_call = e_cfnr_release = 0;
1934 if (e_ext.number[0])
1935 e_dtmf = 1; /* allow dtmf */
1938 /* other calls with no caller id (or not available for the extension) and force colp */
1939 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
1940 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
1941 if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT || portlist->port_type==PORT_TYPE_GSM_OUT) { /* external extension answered */
1942 port = find_port_id(portlist->port_id);
1944 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
1945 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1950 /* send connect to join */
1951 if (ea_endpoint->ep_join_id) {
1952 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1953 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1954 message_put(message);
1956 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1957 message->param.audiopath = 1;
1958 message_put(message);
1959 } else if (!e_adminid) {
1961 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
1962 SCPY(e_ext.number, e_cbcaller);
1963 new_state(EPOINT_STATE_IN_OVERLAP);
1964 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1966 /* get extension's info about terminal */
1967 if (!read_extension(&e_ext, e_ext.number)) {
1968 /* extension doesn't exist */
1969 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1970 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1971 new_state(EPOINT_STATE_OUT_DISCONNECT);
1972 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1976 /* put prefix in front of e_cbdialing */
1977 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
1978 SCPY(e_dialinginfo.id, buffer);
1979 e_dialinginfo.itype = INFO_ITYPE_ISDN;
1980 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1982 /* use caller id (or if exist: id_next_call) for this call */
1983 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1984 SCPY(e_callerinfo.extension, e_ext.number);
1985 if (e_ext.id_next_call_present >= 0) {
1986 SCPY(e_callerinfo.id, e_ext.id_next_call);
1987 e_callerinfo.present = e_ext.id_next_call_present;
1988 e_callerinfo.ntype = e_ext.id_next_call_type;
1989 e_ext.id_next_call_present = -1;
1990 /* extension is written */
1991 write_extension(&e_ext, e_ext.number);
1993 SCPY(e_callerinfo.id, e_ext.callerid);
1994 e_callerinfo.present = e_ext.callerid_present;
1995 e_callerinfo.ntype = e_ext.callerid_type;
1997 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1999 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2002 /* check if caller id is NOT authenticated */
2003 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2004 /* make call state to enter password */
2005 new_state(EPOINT_STATE_IN_OVERLAP);
2006 e_action = &action_password_write;
2007 e_match_timeout = 0;
2008 e_match_to_action = NULL;
2009 e_dialinginfo.id[0] = '\0';
2010 e_extdialing = strchr(e_dialinginfo.id, '\0');
2011 e_password_timeout = now+20;
2014 /* incoming call (callback) */
2015 e_ruleset = ruleset_main;
2017 e_rule = e_ruleset->rule_first;
2019 e_extdialing = e_dialinginfo.id;
2020 if (e_dialinginfo.id[0]) {
2021 set_tone(portlist, "dialing");
2024 set_tone(portlist, "dialpbx");
2027 } else { /* testcall */
2028 set_tone(portlist, "hold");
2031 /* start recording if enabled, not when answering machine answers */
2032 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)) {
2033 /* check if we are a terminal */
2034 if (e_ext.number[0] == '\0')
2035 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2037 port = find_port_id(portlist->port_id);
2039 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2044 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2045 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2047 struct lcr_msg *message;
2049 unsigned int port_id = portlist->port_id;
2053 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2055 /* signal to call tool */
2056 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2058 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2059 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2060 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2065 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);
2066 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2067 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2069 /* check if we have more than one portlist relation and we just ignore the disconnect */
2070 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2071 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2072 portlist = ea_endpoint->ep_portlist;
2074 if (portlist->port_id == port_id)
2076 portlist = portlist->next;
2079 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2080 if (message_type != MESSAGE_RELEASE) {
2081 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2082 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2083 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2084 message_put(message);
2085 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2087 ea_endpoint->free_portlist(portlist);
2088 return; /* one relation removed */
2090 if (e_state == EPOINT_STATE_CONNECT) {
2091 /* use cause from port after connect */
2092 cause = param->disconnectinfo.cause;
2093 location = param->disconnectinfo.location;
2095 /* use multipoint cause if no connect yet */
2096 if (e_multipoint_cause) {
2097 cause = e_multipoint_cause;
2098 location = e_multipoint_location;
2100 cause = CAUSE_NOUSER;
2101 location = LOCATION_PRIVATE_LOCAL;
2105 e_cfnr_call = e_cfnr_release = 0;
2107 /* process hangup */
2108 process_hangup(e_join_cause, e_join_location);
2109 e_multipoint_cause = 0;
2110 e_multipoint_location = 0;
2112 if (message_type == MESSAGE_DISCONNECT) {
2113 /* tone to disconnected end */
2114 SPRINT(buffer, "cause_%02x", cause);
2115 if (ea_endpoint->ep_portlist)
2116 set_tone(ea_endpoint->ep_portlist, buffer);
2118 new_state(EPOINT_STATE_IN_DISCONNECT);
2121 if (ea_endpoint->ep_join_id) {
2122 int haspatterns = 0;
2123 /* check if pattern is available */
2124 if (ea_endpoint->ep_portlist)
2125 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2126 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
2127 && message_type != MESSAGE_RELEASE) // if we release, we are done
2130 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2131 /* indicate patterns */
2132 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2133 message_put(message);
2134 /* connect audio, if not already */
2135 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2136 message->param.audiopath = 1;
2137 message_put(message);
2138 /* send disconnect */
2139 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2140 memcpy(&message->param, param, sizeof(union parameter));
2141 message_put(message);
2142 /* disable encryption if disconnected */
2143 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2145 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2148 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2151 if (message_type == MESSAGE_RELEASE)
2152 ea_endpoint->free_portlist(portlist);
2153 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */
2154 return; /* must exit here */
2157 /* port MESSAGE_TIMEOUT */
2158 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2162 trace_header("TIMEOUT", DIRECTION_IN);
2163 message_type = MESSAGE_DISCONNECT;
2164 switch (param->state) {
2165 case PORT_STATE_OUT_SETUP:
2166 case PORT_STATE_OUT_OVERLAP:
2167 add_trace("state", NULL, "outgoing setup/dialing");
2169 /* no user responding */
2170 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2171 return; /* must exit here */
2173 case PORT_STATE_IN_SETUP:
2174 case PORT_STATE_IN_OVERLAP:
2175 add_trace("state", NULL, "incoming setup/dialing");
2176 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2177 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2180 case PORT_STATE_OUT_PROCEEDING:
2181 add_trace("state", NULL, "outgoing proceeding");
2183 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2184 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2185 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2186 return; /* must exit here */
2188 case PORT_STATE_IN_PROCEEDING:
2189 add_trace("state", NULL, "incoming proceeding");
2190 param->disconnectinfo.cause = CAUSE_NOUSER;
2191 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2194 case PORT_STATE_OUT_ALERTING:
2195 add_trace("state", NULL, "outgoing alerting");
2197 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2198 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2199 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2200 return; /* must exit here */
2202 case PORT_STATE_CONNECT:
2203 add_trace("state", NULL, "connect");
2205 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2206 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2207 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2208 return; /* must exit here */
2210 case PORT_STATE_IN_ALERTING:
2211 add_trace("state", NULL, "incoming alerting");
2212 param->disconnectinfo.cause = CAUSE_NOANSWER;
2213 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2216 case PORT_STATE_IN_DISCONNECT:
2217 case PORT_STATE_OUT_DISCONNECT:
2218 add_trace("state", NULL, "disconnect");
2220 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2221 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2222 return; /* must exit here */
2225 param->disconnectinfo.cause = 31; /* normal unspecified */
2226 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2229 /* release call, disconnect isdn */
2231 new_state(EPOINT_STATE_OUT_DISCONNECT);
2232 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2233 SCPY(e_tone, cause);
2235 set_tone(portlist, cause);
2236 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2237 portlist = portlist->next;
2239 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2242 /* port MESSAGE_NOTIFY */
2243 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2245 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2247 struct lcr_msg *message;
2248 const char *logtext = "";
2251 /* signal to call tool */
2252 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);
2253 if (param->notifyinfo.notify) {
2254 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2257 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2258 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2259 case INFO_NOTIFY_REMOTE_HOLD:
2260 case INFO_NOTIFY_USER_SUSPENDED:
2261 /* tell call about it */
2262 if (ea_endpoint->ep_join_id) {
2263 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2264 message->param.audiopath = 0;
2265 message_put(message);
2269 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2270 case INFO_NOTIFY_USER_RESUMED:
2271 /* set volume of rx and tx */
2272 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2273 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2275 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2276 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2277 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2278 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2279 message_put(message);
2281 /* set current tone */
2283 set_tone(portlist, e_tone);
2284 /* tell call about it */
2285 if (ea_endpoint->ep_join_id) {
2286 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2287 message->param.audiopath = 1;
2288 message_put(message);
2293 /* get name of notify */
2294 switch(param->notifyinfo.notify) {
2299 logtext = "USER_SUSPENDED";
2302 logtext = "BEARER_SERVICE_CHANGED";
2305 logtext = "USER_RESUMED";
2308 logtext = "CONFERENCE_ESTABLISHED";
2311 logtext = "CONFERENCE_DISCONNECTED";
2314 logtext = "OTHER_PARTY_ADDED";
2317 logtext = "ISOLATED";
2320 logtext = "REATTACHED";
2323 logtext = "OTHER_PARTY_ISOLATED";
2326 logtext = "OTHER_PARTY_REATTACHED";
2329 logtext = "OTHER_PARTY_SPLIT";
2332 logtext = "OTHER_PARTY_DISCONNECTED";
2335 logtext = "CONFERENCE_FLOATING";
2338 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2341 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2344 logtext = "CALL_IS_A_WAITING_CALL";
2347 logtext = "DIVERSION_ACTIVATED";
2350 logtext = "RESERVED_CT_1";
2353 logtext = "RESERVED_CT_2";
2356 logtext = "REVERSE_CHARGING";
2359 logtext = "REMOTE_HOLD";
2362 logtext = "REMOTE_RETRIEVAL";
2365 logtext = "CALL_IS_DIVERTING";
2368 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2373 /* notify call if available */
2374 if (ea_endpoint->ep_join_id) {
2375 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2376 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2377 message_put(message);
2382 /* port MESSAGE_FACILITY */
2383 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2385 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2387 struct lcr_msg *message;
2389 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2390 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2391 message_put(message);
2394 /* port MESSAGE_SUSPEND */
2395 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2396 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2398 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2400 /* epoint is now parked */
2401 ea_endpoint->ep_park = 1;
2402 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2403 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2405 /* remove port relation */
2406 ea_endpoint->free_portlist(portlist);
2409 /* port MESSAGE_RESUME */
2410 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2411 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2413 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2415 /* epoint is now resumed */
2416 ea_endpoint->ep_park = 0;
2421 /* port sends message to the endpoint
2423 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2425 struct port_list *portlist;
2427 portlist = ea_endpoint->ep_portlist;
2429 if (port_id == portlist->port_id)
2431 portlist = portlist->next;
2434 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);
2438 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2439 switch(message_type) {
2440 case MESSAGE_DATA: /* data from port */
2441 /* check if there is a call */
2442 if (!ea_endpoint->ep_join_id)
2444 /* continue if only one portlist */
2445 if (ea_endpoint->ep_portlist->next != NULL)
2447 /* forward message */
2448 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2451 case MESSAGE_TONE_EOF: /* tone is end of file */
2452 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2454 if (e_action->index == ACTION_VBOX_PLAY) {
2457 if (e_action->index == ACTION_EFI) {
2463 case MESSAGE_TONE_COUNTER: /* counter info received */
2464 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);
2466 if (e_action->index == ACTION_VBOX_PLAY) {
2467 e_vbox_counter = param->counter.current;
2468 if (param->counter.max >= 0)
2469 e_vbox_counter_max = param->counter.max;
2473 /* PORT sends SETUP message */
2475 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);
2476 if (e_state!=EPOINT_STATE_IDLE) {
2477 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2480 port_setup(portlist, message_type, param);
2483 /* PORT sends INFORMATION message */
2484 case MESSAGE_INFORMATION: /* additional digits received */
2485 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);
2486 port_information(portlist, message_type, param);
2489 /* PORT sends FACILITY message */
2490 case MESSAGE_FACILITY:
2491 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2492 port_facility(portlist, message_type, param);
2495 /* PORT sends DTMF message */
2496 case MESSAGE_DTMF: /* dtmf digits received */
2497 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);
2498 port_dtmf(portlist, message_type, param);
2501 /* PORT sends CRYPT message */
2502 case MESSAGE_CRYPT: /* crypt response received */
2503 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2504 port_crypt(portlist, message_type, param);
2507 /* PORT sends MORE message */
2508 case MESSAGE_OVERLAP:
2509 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);
2510 if (e_state != EPOINT_STATE_OUT_SETUP) {
2511 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);
2514 port_overlap(portlist, message_type, param);
2517 /* PORT sends PROCEEDING message */
2518 case MESSAGE_PROCEEDING: /* port is proceeding */
2519 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);
2520 if (e_state!=EPOINT_STATE_OUT_SETUP
2521 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2522 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);
2525 port_proceeding(portlist, message_type, param);
2528 /* PORT sends ALERTING message */
2529 case MESSAGE_ALERTING:
2530 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);
2531 if (e_state!=EPOINT_STATE_OUT_SETUP
2532 && e_state!=EPOINT_STATE_OUT_OVERLAP
2533 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2534 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);
2537 port_alerting(portlist, message_type, param);
2540 /* PORT sends CONNECT message */
2541 case MESSAGE_CONNECT:
2542 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);
2543 if (e_state!=EPOINT_STATE_OUT_SETUP
2544 && e_state!=EPOINT_STATE_OUT_OVERLAP
2545 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2546 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2547 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2550 port_connect(portlist, message_type, param);
2553 /* PORT sends DISCONNECT message */
2554 case MESSAGE_DISCONNECT: /* port is disconnected */
2555 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);
2556 port_disconnect_release(portlist, message_type, param);
2559 /* PORT sends a RELEASE message */
2560 case MESSAGE_RELEASE: /* port releases */
2561 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);
2562 /* portlist is release at port_disconnect_release, thanx Paul */
2563 port_disconnect_release(portlist, message_type, param);
2566 /* PORT sends a TIMEOUT message */
2567 case MESSAGE_TIMEOUT:
2568 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);
2569 port_timeout(portlist, message_type, param);
2570 break; /* release */
2572 /* PORT sends a NOTIFY message */
2573 case MESSAGE_NOTIFY:
2574 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);
2575 port_notify(portlist, message_type, param);
2578 /* PORT sends a SUSPEND message */
2579 case MESSAGE_SUSPEND:
2580 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);
2581 port_suspend(portlist, message_type, param);
2582 break; /* suspend */
2584 /* PORT sends a RESUME message */
2585 case MESSAGE_RESUME:
2586 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);
2587 port_resume(portlist, message_type, param);
2591 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2592 /* port assigns bchannel */
2593 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2594 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);
2595 /* only one port is expected to be connected to bchannel */
2596 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2597 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2603 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);
2606 /* Note: this endpoint may be destroyed, so we MUST return */
2610 /* messages from join
2612 /* join MESSAGE_CRYPT */
2613 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2615 switch(param->crypt.type) {
2616 /* message from remote port to "crypt manager" */
2617 case CU_ACTK_REQ: /* activate key-exchange */
2618 case CU_ACTS_REQ: /* activate shared key */
2619 case CU_DACT_REQ: /* deactivate */
2620 case CU_INFO_REQ: /* request last info message */
2621 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2624 /* message from "crypt manager" to user */
2625 case CU_ACTK_CONF: /* key-echange done */
2626 case CU_ACTS_CONF: /* shared key done */
2627 case CU_DACT_CONF: /* deactivated */
2628 case CU_DACT_IND: /* deactivated */
2629 case CU_ERROR_IND: /* receive error message */
2630 case CU_INFO_IND: /* receive info message */
2631 case CU_INFO_CONF: /* receive info message */
2632 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2636 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);
2640 /* join MESSAGE_INFORMATION */
2641 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2643 struct lcr_msg *message;
2648 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2649 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2650 message_put(message);
2651 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2652 portlist = portlist->next;
2656 /* join MESSAGE_FACILITY */
2657 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2659 struct lcr_msg *message;
2661 if (!e_ext.facility && e_ext.number[0]) {
2666 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2667 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2668 message_put(message);
2669 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2670 portlist = portlist->next;
2674 /* join MESSAGE_MORE */
2675 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2677 struct lcr_msg *message;
2679 new_state(EPOINT_STATE_IN_OVERLAP);
2682 if (e_join_pattern && e_ext.own_setup) {
2683 /* disconnect audio */
2684 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2685 message->param.audiopath = 0;
2686 message_put(message);
2688 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2689 if (e_dialinginfo.id[0])
2690 set_tone(portlist, "dialing");
2692 set_tone(portlist, "dialtone");
2695 if (e_dialinginfo.id[0]) {
2696 set_tone(portlist, "dialing");
2698 if (e_ext.number[0])
2699 set_tone(portlist, "dialpbx");
2701 set_tone(portlist, "dialtone");
2705 /* join MESSAGE_PROCEEDING */
2706 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2708 struct lcr_msg *message;
2710 new_state(EPOINT_STATE_IN_PROCEEDING);
2712 /* own proceeding tone */
2713 if (e_join_pattern) {
2714 /* connect / disconnect audio */
2715 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2716 if (e_ext.own_proceeding)
2717 message->param.audiopath = 0;
2719 message->param.audiopath = 1;
2720 message_put(message);
2722 // UCPY(e_join_tone, "proceeding");
2724 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2725 message_put(message);
2726 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2728 set_tone(portlist, "proceeding");
2731 /* join MESSAGE_ALERTING */
2732 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2734 struct lcr_msg *message;
2736 new_state(EPOINT_STATE_IN_ALERTING);
2738 /* own alerting tone */
2739 if (e_join_pattern) {
2740 /* connect / disconnect audio */
2741 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2742 if (e_ext.own_alerting)
2743 message->param.audiopath = 0;
2745 message->param.audiopath = 1;
2746 message_put(message);
2749 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2750 message_put(message);
2751 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2753 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2754 set_tone(portlist, "ringing");
2757 if (e_ext.number[0])
2758 set_tone(portlist, "ringpbx");
2760 set_tone(portlist, "ringing");
2763 /* join MESSAGE_CONNECT */
2764 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2766 struct lcr_msg *message;
2768 new_state(EPOINT_STATE_CONNECT);
2769 // UCPY(e_join_tone, "");
2771 if (e_ext.number[0])
2772 e_dtmf = 1; /* allow dtmf */
2775 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2777 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2778 memcpy(&message->param, param, sizeof(union parameter));
2780 /* screen clip if prefix is required */
2781 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2782 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2783 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2784 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2787 /* use internal caller id */
2788 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2789 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2790 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2793 /* handle restricted caller ids */
2794 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);
2795 /* display callerid if desired for extension */
2796 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));
2798 /* use conp, if enabld */
2799 // if (!e_ext.centrex)
2800 // message->param.connectinfo.name[0] = '\0';
2803 message_put(message);
2804 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2806 set_tone(portlist, NULL);
2808 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2809 message->param.audiopath = 1;
2810 message_put(message);
2814 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2815 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2818 struct lcr_msg *message;
2819 struct port_list *portlist = NULL;
2822 /* be sure that we are active */
2824 e_tx_state = NOTIFY_STATE_ACTIVE;
2826 /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
2827 if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2828 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2830 /* set time for power dialing */
2831 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
2834 /* set redial tone */
2835 if (ea_endpoint->ep_portlist) {
2838 set_tone(ea_endpoint->ep_portlist, "redial");
2839 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);
2840 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2841 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2842 new_state(EPOINT_STATE_IN_PROCEEDING);
2843 if (ea_endpoint->ep_portlist) {
2844 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2845 message_put(message);
2846 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2848 /* caused the error, that the first knock sound was not there */
2849 /* set_tone(portlist, "proceeding"); */
2851 /* send display of powerdialing */
2852 if (e_ext.display_dialing) {
2853 portlist = ea_endpoint->ep_portlist;
2855 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2857 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2859 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2860 message_put(message);
2861 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2862 portlist = portlist->next;
2871 if ((e_state!=EPOINT_STATE_CONNECT
2872 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2873 && e_state!=EPOINT_STATE_IN_OVERLAP
2874 && e_state!=EPOINT_STATE_IN_PROCEEDING
2875 && e_state!=EPOINT_STATE_IN_ALERTING)
2876 || !ea_endpoint->ep_portlist) { /* or no port */
2877 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2878 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */
2879 return; /* must exit here */
2882 if (!e_join_cause) {
2883 e_join_cause = param->disconnectinfo.cause;
2884 e_join_location = param->disconnectinfo.location;
2887 /* on release we need the audio again! */
2888 if (message_type == MESSAGE_RELEASE) {
2890 ea_endpoint->ep_join_id = 0;
2892 /* disconnect and select tone */
2893 new_state(EPOINT_STATE_OUT_DISCONNECT);
2894 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2895 /* if own_cause, we must release the join */
2896 if (e_ext.own_cause /* own cause */
2897 || !e_join_pattern) { /* no patterns */
2898 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);
2899 if (message_type != MESSAGE_RELEASE)
2900 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2902 } else { /* else we enable audio */
2903 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2904 message->param.audiopath = 1;
2905 message_put(message);
2907 /* send disconnect message */
2908 SCPY(e_tone, cause);
2909 portlist = ea_endpoint->ep_portlist;
2911 set_tone(portlist, cause);
2912 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2913 portlist = portlist->next;
2917 /* join MESSAGE_SETUP */
2918 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2920 struct lcr_msg *message;
2921 // struct interface *interface;
2923 /* if we already in setup state, we just update the dialing with new digits */
2924 if (e_state == EPOINT_STATE_OUT_SETUP
2925 || e_state == EPOINT_STATE_OUT_OVERLAP) {
2926 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
2927 /* if digits changed, what we have already dialed */
2928 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
2929 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);
2930 /* release all ports */
2931 while((portlist = ea_endpoint->ep_portlist)) {
2932 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2933 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2934 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2935 message_put(message);
2936 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2937 ea_endpoint->free_portlist(portlist);
2940 /* disconnect audio */
2941 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2942 message->param.audiopath = 0;
2943 message_put(message);
2945 /* get dialing info */
2946 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
2947 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2948 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
2949 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
2950 new_state(EPOINT_STATE_OUT_OVERLAP);
2953 e_redial = now_d + 1; /* set redial one second in the future */
2956 /* if we have a pending redial, so we just adjust the dialing number */
2958 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);
2959 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2962 if (!ea_endpoint->ep_portlist) {
2963 PERROR("ERROR: overlap dialing to a NULL port relation\n");
2965 if (ea_endpoint->ep_portlist->next) {
2966 PERROR("ERROR: overlap dialing to a port_list port relation\n");
2968 if (e_state == EPOINT_STATE_OUT_SETUP) {
2970 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);
2971 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2974 /* get what we have not dialed yet */
2975 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));
2976 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2977 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2978 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
2979 message_put(message);
2980 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2982 /* always store what we have dialed or queued */
2983 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2987 if (e_state != EPOINT_STATE_IDLE) {
2988 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2991 /* if an internal extension is dialed, copy that number */
2992 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
2993 SCPY(e_ext.number, param->setup.dialinginfo.id);
2994 /* if an internal extension is dialed, get extension's info about caller */
2995 if (e_ext.number[0]) {
2996 if (!read_extension(&e_ext, e_ext.number)) {
2997 e_ext.number[0] = '\0';
2998 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3002 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3003 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3004 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3005 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3007 /* process (voice over) data calls */
3008 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3009 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3010 memset(&e_capainfo, 0, sizeof(e_capainfo));
3011 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3012 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3013 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3016 new_state(EPOINT_STATE_OUT_SETUP);
3017 /* call special setup routine */
3021 /* join MESSAGE_mISDNSIGNAL */
3022 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3024 struct lcr_msg *message;
3027 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3028 memcpy(&message->param, param, sizeof(union parameter));
3029 message_put(message);
3030 portlist = portlist->next;
3034 /* join MESSAGE_NOTIFY */
3035 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3037 struct lcr_msg *message;
3040 if (param->notifyinfo.notify) {
3041 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3042 // /* if notification was generated locally, we turn hold music on/off */
3043 // if (param->notifyinfo.local)
3044 // 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)
3048 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3049 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3051 set_tone(portlist, "");
3052 portlist = portlist->next;
3055 portlist = ea_endpoint->ep_portlist;
3060 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3062 set_tone(portlist, "hold");
3063 portlist = portlist->next;
3065 portlist = ea_endpoint->ep_portlist;
3070 /* save new state */
3071 e_tx_state = new_state;
3074 /* notify port(s) about it */
3076 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3077 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3078 /* handle restricted caller ids */
3079 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3080 /* display callerid if desired for extension */
3081 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));
3082 message_put(message);
3083 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3084 portlist = portlist->next;
3088 /* JOIN sends messages to the endpoint
3090 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3092 struct port_list *portlist;
3093 struct lcr_msg *message;
3096 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3100 portlist = ea_endpoint->ep_portlist;
3102 /* send MESSAGE_DATA to port */
3103 if (message_type == MESSAGE_DATA) {
3104 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3105 /* skip if no port relation */
3108 /* skip if more than one port relation */
3111 /* forward audio data to port */
3112 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3117 // 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);
3118 switch(message_type) {
3119 /* JOIN SENDS TONE message */
3121 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);
3122 set_tone(portlist, param->tone.name);
3125 /* JOIN SENDS CRYPT message */
3127 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);
3128 join_crypt(portlist, message_type, param);
3131 /* JOIN sends INFORMATION message */
3132 case MESSAGE_INFORMATION:
3133 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);
3134 join_information(portlist, message_type, param);
3137 /* JOIN sends FACILITY message */
3138 case MESSAGE_FACILITY:
3139 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);
3140 join_facility(portlist, message_type, param);
3143 /* JOIN sends OVERLAP message */
3144 case MESSAGE_OVERLAP:
3145 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);
3146 if (e_state!=EPOINT_STATE_IN_SETUP
3147 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3148 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3151 join_overlap(portlist, message_type, param);
3154 /* JOIN sends PROCEEDING message */
3155 case MESSAGE_PROCEEDING:
3156 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);
3157 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3158 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3161 join_proceeding(portlist, message_type, param);
3164 /* JOIN sends ALERTING message */
3165 case MESSAGE_ALERTING:
3166 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);
3167 if (e_state!=EPOINT_STATE_IN_OVERLAP
3168 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3169 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3172 join_alerting(portlist, message_type, param);
3175 /* JOIN sends CONNECT message */
3176 case MESSAGE_CONNECT:
3177 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);
3178 if (e_state!=EPOINT_STATE_IN_OVERLAP
3179 && e_state!=EPOINT_STATE_IN_PROCEEDING
3180 && e_state!=EPOINT_STATE_IN_ALERTING) {
3181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3184 join_connect(portlist, message_type, param);
3187 /* JOIN sends DISCONNECT/RELEASE message */
3188 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3189 case MESSAGE_RELEASE: /* JOIN releases */
3190 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);
3191 join_disconnect_release(message_type, param);
3194 /* JOIN sends SETUP message */
3196 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);
3197 join_setup(portlist, message_type, param);
3200 /* JOIN sends special mISDNSIGNAL message */
3201 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3202 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);
3203 join_mISDNsignal(portlist, message_type, param);
3207 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3208 /* JOIN requests bchannel */
3209 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3210 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel assignment %d from join.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type);
3211 /* only one port is expected to be connected to bchannel */
3218 set_tone(portlist, NULL);
3219 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3220 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3224 /* JOIN has pattern available */
3225 case MESSAGE_PATTERN: /* indicating pattern available */
3226 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);
3227 if (!e_join_pattern) {
3228 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3232 set_tone(portlist, NULL);
3233 portlist = portlist->next;
3235 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3236 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3237 message->param.audiopath = 1;
3238 message_put(message);
3242 /* JOIN has no pattern available */
3243 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3244 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);
3245 if (e_join_pattern) {
3246 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3248 /* disconnect our audio tx and rx */
3249 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3250 message->param.audiopath = 0;
3251 message_put(message);
3256 /* JOIN (dunno at the moment) */
3257 case MESSAGE_REMOTE_AUDIO:
3258 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);
3259 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3260 message->param.audiopath = param->channel;
3261 message_put(message);
3265 /* JOIN sends a notify message */
3266 case MESSAGE_NOTIFY:
3267 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);
3268 join_notify(portlist, message_type, param);
3271 /* JOIN wants keypad / dtmf */
3272 case MESSAGE_ENABLEKEYPAD:
3273 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);
3276 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3281 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);
3286 /* pick_join will connect the first incoming call found. the endpoint
3287 * will receivce a MESSAGE_CONNECT.
3289 int match_list(char *list, char *item)
3291 char *end, *next = NULL;
3293 /* no list make matching */
3298 /* eliminate white spaces */
3299 while (*list <= ' ')
3305 /* if end of list is reached, we return */
3306 if (list[0] == '\0')
3308 /* if we have more than one entry (left) */
3309 if ((end = strchr(list, ',')))
3312 next = end = strchr(list, '\0');
3313 while (*(end-1) <= ' ')
3315 /* if string part matches item */
3316 if (!strncmp(list, item, end-list))
3322 void EndpointAppPBX::pick_join(char *extensions)
3324 struct lcr_msg *message;
3325 struct port_list *portlist;
3327 class EndpointAppPBX *eapp, *found;
3329 class JoinPBX *joinpbx;
3330 struct join_relation *relation;
3333 /* find an endpoint that is ringing internally or vbox with higher priority */
3336 eapp = apppbx_first;
3338 if (eapp!=this && ea_endpoint->ep_portlist) {
3339 portlist = eapp->ea_endpoint->ep_portlist;
3341 if ((port = find_port_id(portlist->port_id))) {
3342 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3343 if (match_list(extensions, eapp->e_ext.number)) {
3349 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3350 && port->p_state==PORT_STATE_OUT_ALERTING)
3351 if (match_list(extensions, eapp->e_ext.number)) {
3355 portlist = portlist->next;
3363 /* if no endpoint found */
3365 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);
3367 set_tone(ea_endpoint->ep_portlist, "cause_10");
3368 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3369 new_state(EPOINT_STATE_OUT_DISCONNECT);
3374 if (ea_endpoint->ep_join_id) {
3375 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3378 if (!eapp->ea_endpoint->ep_join_id) {
3379 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3382 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3384 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3387 if (join->j_type != JOIN_TYPE_PBX) {
3388 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3391 joinpbx = (class JoinPBX *)join;
3392 relation = joinpbx->j_relation;
3394 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3397 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3398 relation = relation->next;
3400 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3405 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3407 if (options.deb & DEBUG_EPOINT) {
3408 class Join *debug_c = join_first;
3409 class Endpoint *debug_e = epoint_first;
3410 class Port *debug_p = port_first;
3412 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3414 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3416 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3417 debug_c = debug_c->next;
3419 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3421 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3422 debug_e = debug_e->next;
3424 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3426 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3427 debug_p = debug_p->next;
3432 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3433 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3434 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3436 /* connnecting our endpoint */
3437 new_state(EPOINT_STATE_CONNECT);
3438 if (e_ext.number[0])
3440 set_tone(ea_endpoint->ep_portlist, NULL);
3442 /* now we send a release to the ringing endpoint */
3443 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3444 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3445 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3446 message_put(message);
3448 /* we send a connect to the join with our caller id */
3449 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3450 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3451 message->param.connectinfo.present = e_callerinfo.present;
3452 message->param.connectinfo.screen = e_callerinfo.screen;
3453 message->param.connectinfo.itype = e_callerinfo.itype;
3454 message->param.connectinfo.ntype = e_callerinfo.ntype;
3455 message_put(message);
3457 /* we send a connect to our port with the remote callerid */
3458 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3459 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3460 message->param.connectinfo.present = eapp->e_callerinfo.present;
3461 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3462 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3463 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3464 /* handle restricted caller ids */
3465 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);
3466 /* display callerid if desired for extension */
3467 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));
3468 message_put(message);
3470 /* we send a connect to the audio path (not for vbox) */
3471 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3472 message->param.audiopath = 1;
3473 message_put(message);
3475 /* beeing paranoid, we make call update */
3476 joinpbx->j_updatebridge = 1;
3478 if (options.deb & DEBUG_EPOINT) {
3479 class Join *debug_c = join_first;
3480 class Endpoint *debug_e = epoint_first;
3481 class Port *debug_p = port_first;
3483 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3485 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3487 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3488 debug_c = debug_c->next;
3490 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3492 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3493 debug_e = debug_e->next;
3495 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3497 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3498 debug_p = debug_p->next;
3504 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3506 void EndpointAppPBX::join_join(void)
3508 struct lcr_msg *message;
3509 struct join_relation *our_relation, *other_relation;
3510 struct join_relation **our_relation_pointer, **other_relation_pointer;
3511 class Join *our_join, *other_join;
3512 class JoinPBX *our_joinpbx, *other_joinpbx;
3513 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3514 class Port *our_port, *other_port;
3515 class Pdss1 *our_pdss1, *other_pdss1;
3517 /* are we a candidate to join a join */
3518 our_join = find_join_id(ea_endpoint->ep_join_id);
3520 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3523 if (our_join->j_type != JOIN_TYPE_PBX) {
3524 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3527 our_joinpbx = (class JoinPBX *)our_join;
3528 if (!ea_endpoint->ep_portlist) {
3529 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3532 if (!e_ext.number[0]) {
3533 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3536 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3538 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3541 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3542 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3545 our_pdss1 = (class Pdss1 *)our_port;
3547 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3548 other_eapp = apppbx_first;
3550 if (other_eapp == this) {
3551 other_eapp = other_eapp->next;
3554 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);
3555 if (other_eapp->e_ext.number[0] /* has terminal */
3556 && other_eapp->ea_endpoint->ep_portlist /* has port */
3557 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3558 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3559 if (other_port) { /* port still exists */
3560 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3561 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3562 other_pdss1 = (class Pdss1 *)other_port;
3563 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);
3564 if (other_pdss1->p_m_hold /* port is on hold */
3565 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3566 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3569 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3572 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3575 other_eapp = other_eapp->next;
3578 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn interface with port on hold.\n", ea_endpoint->ep_serial);
3581 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port on hold found.\n", ea_endpoint->ep_serial);
3583 /* if we have the same join */
3584 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3585 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we an the other have the same join.\n", ea_endpoint->ep_serial);
3588 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3590 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3593 if (other_join->j_type != JOIN_TYPE_PBX) {
3594 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3597 other_joinpbx = (class JoinPBX *)other_join;
3598 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3599 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3603 /* remove relation to endpoint for join on hold */
3604 other_relation = other_joinpbx->j_relation;
3605 other_relation_pointer = &other_joinpbx->j_relation;
3606 while(other_relation) {
3607 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3608 /* detach other endpoint on hold */
3609 *other_relation_pointer = other_relation->next;
3610 FREE(other_relation, sizeof(struct join_relation));
3612 other_relation = *other_relation_pointer;
3613 other_eapp->ea_endpoint->ep_join_id = 0;
3617 /* change join/hold pointer of endpoint to the new join */
3618 temp_epoint = find_epoint_id(other_relation->epoint_id);
3620 if (temp_epoint->ep_join_id == other_join->j_serial)
3621 temp_epoint->ep_join_id = our_join->j_serial;
3624 other_relation_pointer = &other_relation->next;
3625 other_relation = other_relation->next;
3627 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3629 /* join call relations */
3630 our_relation = our_joinpbx->j_relation;
3631 our_relation_pointer = &our_joinpbx->j_relation;
3632 while(our_relation) {
3633 our_relation_pointer = &our_relation->next;
3634 our_relation = our_relation->next;
3636 *our_relation_pointer = other_joinpbx->j_relation;
3637 other_joinpbx->j_relation = NULL;
3638 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3640 /* release endpoint on hold */
3641 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3642 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3643 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3644 message_put(message);
3646 /* if we are not a partyline, we get partyline state from other join */
3647 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3649 /* remove empty join */
3651 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3653 /* mixer must update */
3654 our_joinpbx->j_updatebridge = 1; /* update mixer flag */
3656 /* we send a retrieve to that endpoint */
3657 // mixer will update the hold-state of the join and send it to the endpoints is changes
3661 /* check if we have an external call
3662 * this is used to check for encryption ability
3664 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3666 struct join_relation *relation;
3668 class JoinPBX *joinpbx;
3669 class Endpoint *epoint;
3671 /* some paranoia check */
3672 if (!ea_endpoint->ep_portlist) {
3673 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3674 *errstr = "No Call";
3677 if (!e_ext.number[0]) {
3678 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3679 *errstr = "No Call";
3683 /* check if we have a join with 2 parties */
3684 join = find_join_id(ea_endpoint->ep_join_id);
3686 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3687 *errstr = "No Call";
3690 if (join->j_type != JOIN_TYPE_PBX) {
3691 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3692 *errstr = "No PBX Call";
3695 joinpbx = (class JoinPBX *)join;
3696 relation = joinpbx->j_relation;
3698 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3699 *errstr = "No Call";
3702 if (!relation->next) {
3703 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3704 *errstr = "No Call";
3707 if (relation->next->next) {
3708 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3709 *errstr = "Err: Conference";
3712 if (relation->epoint_id == ea_endpoint->ep_serial) {
3713 relation = relation->next;
3714 if (relation->epoint_id == ea_endpoint->ep_serial) {
3715 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3716 *errstr = "Software Error";
3721 /* check remote port for external call */
3722 epoint = find_epoint_id(relation->epoint_id);
3724 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3725 *errstr = "No Call";
3728 if (!epoint->ep_portlist) {
3729 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3730 *errstr = "No Call";
3733 *port = find_port_id(epoint->ep_portlist->port_id);
3735 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3736 *errstr = "No Call";
3739 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3740 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3741 *errstr = "No Ext Call";
3744 if ((*port)->p_state != PORT_STATE_CONNECT) {
3745 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3746 *errstr = "No Ext Connect";
3752 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3754 const char *logtext = "unknown";
3757 switch(message_type) {
3759 trace_header("SETUP", dir);
3760 if (dir == DIRECTION_OUT)
3761 add_trace("to", NULL, "CH(%lu)", port_id);
3762 if (dir == DIRECTION_IN)
3763 add_trace("from", NULL, "CH(%lu)", port_id);
3764 if (param->setup.callerinfo.extension[0])
3765 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3766 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3767 switch(param->setup.callerinfo.present) {
3768 case INFO_PRESENT_RESTRICTED:
3769 add_trace("caller id", "present", "restricted");
3771 case INFO_PRESENT_ALLOWED:
3772 add_trace("caller id", "present", "allowed");
3775 add_trace("caller id", "present", "not available");
3777 if (param->setup.callerinfo.ntype2) {
3778 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3779 switch(param->setup.callerinfo.present) {
3780 case INFO_PRESENT_RESTRICTED:
3781 add_trace("caller id2", "present", "restricted");
3783 case INFO_PRESENT_ALLOWED:
3784 add_trace("caller id2", "present", "allowed");
3787 add_trace("caller id2", "present", "not available");
3790 if (param->setup.redirinfo.id[0]) {
3791 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3792 switch(param->setup.redirinfo.present) {
3793 case INFO_PRESENT_RESTRICTED:
3794 add_trace("redir'ing", "present", "restricted");
3796 case INFO_PRESENT_ALLOWED:
3797 add_trace("redir'ing", "present", "allowed");
3800 add_trace("redir'ing", "present", "not available");
3803 if (param->setup.dialinginfo.id[0])
3804 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3805 if (param->setup.dialinginfo.display[0])
3806 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3807 if (param->setup.dialinginfo.sending_complete)
3808 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3812 case MESSAGE_OVERLAP:
3813 trace_header("SETUP ACKNOWLEDGE", dir);
3814 if (dir == DIRECTION_OUT)
3815 add_trace("to", NULL, "CH(%lu)", port_id);
3816 if (dir == DIRECTION_IN)
3817 add_trace("from", NULL, "CH(%lu)", port_id);
3821 case MESSAGE_PROCEEDING:
3822 trace_header("PROCEEDING", dir);
3823 if (dir == DIRECTION_OUT)
3824 add_trace("to", NULL, "CH(%lu)", port_id);
3825 if (dir == DIRECTION_IN)
3826 add_trace("from", NULL, "CH(%lu)", port_id);
3830 case MESSAGE_ALERTING:
3831 trace_header("ALERTING", dir);
3832 if (dir == DIRECTION_OUT)
3833 add_trace("to", NULL, "CH(%lu)", port_id);
3834 if (dir == DIRECTION_IN)
3835 add_trace("from", NULL, "CH(%lu)", port_id);
3839 case MESSAGE_CONNECT:
3840 trace_header("CONNECT", dir);
3841 if (dir == DIRECTION_OUT)
3842 add_trace("to", NULL, "CH(%lu)", port_id);
3843 if (dir == DIRECTION_IN)
3844 add_trace("from", NULL, "CH(%lu)", port_id);
3845 if (param->connectinfo.extension[0])
3846 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3847 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3848 switch(param->connectinfo.present) {
3849 case INFO_PRESENT_RESTRICTED:
3850 add_trace("connect id", "present", "restricted");
3852 case INFO_PRESENT_ALLOWED:
3853 add_trace("connect id", "present", "allowed");
3856 add_trace("connect id", "present", "not available");
3858 if (param->connectinfo.display[0])
3859 add_trace("display", NULL, "%s", param->connectinfo.display);
3863 case MESSAGE_DISCONNECT:
3864 case MESSAGE_RELEASE:
3865 if (message_type == MESSAGE_DISCONNECT)
3866 trace_header("DISCONNECT", dir);
3868 trace_header("RELEASE", dir);
3869 if (dir == DIRECTION_OUT)
3870 add_trace("to", NULL, "CH(%lu)", port_id);
3871 if (dir == DIRECTION_IN)
3872 add_trace("from", NULL, "CH(%lu)", port_id);
3873 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3874 switch(param->disconnectinfo.location) {
3876 add_trace("cause", "location", "0-User");
3878 case LOCATION_PRIVATE_LOCAL:
3879 add_trace("cause", "location", "1-Local-PBX");
3881 case LOCATION_PUBLIC_LOCAL:
3882 add_trace("cause", "location", "2-Local-Exchange");
3884 case LOCATION_TRANSIT:
3885 add_trace("cause", "location", "3-Transit");
3887 case LOCATION_PUBLIC_REMOTE:
3888 add_trace("cause", "location", "4-Remote-Exchange");
3890 case LOCATION_PRIVATE_REMOTE:
3891 add_trace("cause", "location", "5-Remote-PBX");
3893 case LOCATION_INTERNATIONAL:
3894 add_trace("cause", "location", "7-International-Exchange");
3896 case LOCATION_BEYOND:
3897 add_trace("cause", "location", "10-Beyond-Interworking");
3900 add_trace("cause", "location", "%d", param->disconnectinfo.location);
3902 if (param->disconnectinfo.display[0])
3903 add_trace("display", NULL, "%s", param->disconnectinfo.display);
3907 case MESSAGE_NOTIFY:
3908 switch(param->notifyinfo.notify) {
3913 logtext = "USER_SUSPENDED";
3916 logtext = "BEARER_SERVICE_CHANGED";
3919 logtext = "USER_RESUMED";
3922 logtext = "CONFERENCE_ESTABLISHED";
3925 logtext = "CONFERENCE_DISCONNECTED";
3928 logtext = "OTHER_PARTY_ADDED";
3931 logtext = "ISOLATED";
3934 logtext = "REATTACHED";
3937 logtext = "OTHER_PARTY_ISOLATED";
3940 logtext = "OTHER_PARTY_REATTACHED";
3943 logtext = "OTHER_PARTY_SPLIT";
3946 logtext = "OTHER_PARTY_DISCONNECTED";
3949 logtext = "CONFERENCE_FLOATING";
3952 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
3955 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
3958 logtext = "CALL_IS_A_WAITING_CALL";
3961 logtext = "DIVERSION_ACTIVATED";
3964 logtext = "RESERVED_CT_1";
3967 logtext = "RESERVED_CT_2";
3970 logtext = "REVERSE_CHARGING";
3973 logtext = "REMOTE_HOLD";
3976 logtext = "REMOTE_RETRIEVAL";
3979 logtext = "CALL_IS_DIVERTING";
3982 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
3986 trace_header("NOTIFY", dir);
3987 if (dir == DIRECTION_OUT)
3988 add_trace("to", NULL, "CH(%lu)", port_id);
3989 if (dir == DIRECTION_IN)
3990 add_trace("from", NULL, "CH(%lu)", port_id);
3991 if (param->notifyinfo.notify)
3992 add_trace("indicator", NULL, "%s", logtext);
3993 if (param->notifyinfo.id[0]) {
3994 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
3995 switch(param->notifyinfo.present) {
3996 case INFO_PRESENT_RESTRICTED:
3997 add_trace("redir'on", "present", "restricted");
3999 case INFO_PRESENT_ALLOWED:
4000 add_trace("redir'on", "present", "allowed");
4003 add_trace("redir'on", "present", "not available");
4006 if (param->notifyinfo.display[0])
4007 add_trace("display", NULL, "%s", param->notifyinfo.display);
4011 case MESSAGE_INFORMATION:
4012 trace_header("INFORMATION", dir);
4013 if (dir == DIRECTION_OUT)
4014 add_trace("to", NULL, "CH(%lu)", port_id);
4015 if (dir == DIRECTION_IN)
4016 add_trace("from", NULL, "CH(%lu)", port_id);
4017 if (param->information.id[0])
4018 add_trace("dialing", NULL, "%s", param->information.id);
4019 if (param->information.display[0])
4020 add_trace("display", NULL, "%s", param->information.display);
4021 if (param->information.sending_complete)
4022 add_trace("complete", NULL, "true", param->information.sending_complete);
4026 case MESSAGE_FACILITY:
4027 trace_header("FACILITY", dir);
4028 if (dir == DIRECTION_OUT)
4029 add_trace("to", NULL, "CH(%lu)", port_id);
4030 if (dir == DIRECTION_IN)
4031 add_trace("from", NULL, "CH(%lu)", port_id);
4036 trace_header("TONE", dir);
4037 if (dir == DIRECTION_OUT)
4038 add_trace("to", NULL, "CH(%lu)", port_id);
4039 if (dir == DIRECTION_IN)
4040 add_trace("from", NULL, "CH(%lu)", port_id);
4041 if (param->tone.name[0]) {
4042 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4043 add_trace("name", NULL, "%s", param->tone.name);
4045 add_trace("off", NULL, NULL);
4049 case MESSAGE_SUSPEND:
4050 case MESSAGE_RESUME:
4051 if (message_type == MESSAGE_SUSPEND)
4052 trace_header("SUSPEND", dir);
4054 trace_header("RESUME", dir);
4055 if (dir == DIRECTION_OUT)
4056 add_trace("to", NULL, "CH(%lu)", port_id);
4057 if (dir == DIRECTION_IN)
4058 add_trace("from", NULL, "CH(%lu)", port_id);
4059 if (param->parkinfo.len)
4060 add_trace("length", NULL, "%d", param->parkinfo.len);
4065 case MESSAGE_BCHANNEL:
4066 trace_header("BCHANNEL", dir);
4067 switch(param->bchannel.type) {
4068 case BCHANNEL_REQUEST:
4069 add_trace("type", NULL, "request");
4071 case BCHANNEL_ASSIGN:
4072 add_trace("type", NULL, "assign");
4074 case BCHANNEL_ASSIGN_ACK:
4075 add_trace("type", NULL, "assign_ack");
4077 case BCHANNEL_REMOVE:
4078 add_trace("type", NULL, "remove");
4080 case BCHANNEL_REMOVE_ACK:
4081 add_trace("type", NULL, "remove_ack");
4084 if (param->bchannel.addr)
4085 add_trace("address", NULL, "%x", param->bchannel.addr);
4091 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4095 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4097 struct lcr_msg *message;
4101 if (!portlist->port_id)
4104 if (!e_connectedmode) {
4105 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4106 message->param.disconnectinfo.cause = cause;
4107 message->param.disconnectinfo.location = location;
4109 SCPY(message->param.disconnectinfo.display, display);
4111 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4113 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4115 SCPY(message->param.notifyinfo.display, display);
4117 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4119 message_put(message);
4120 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);