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;
553 int there_is_an_external = 0;
555 interface = interface_first;
557 /* first find the given interface or, if not given, one with no extension */
560 if (!there_is_an_external && !(ifname && ifname[0])) {
561 trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
562 add_trace("info", NULL, "Add 'external' parameter to interface.conf.");
568 /* check for given interface */
569 if (ifname && ifname[0]) {
570 if (!strcasecmp(interface->name, ifname)) {
571 /* found explicit interface */
572 trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
573 add_trace("interface", NULL, "%s", ifname);
579 if (interface->external) {
580 there_is_an_external = 1;
581 /* found non extension */
582 trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
583 add_trace("interface", NULL, "%s", interface->name);
589 interface = interface->next;
593 /* see if interface has ports */
594 if (!interface->ifport) {
596 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
597 add_trace("interface", NULL, "%s", interface->name);
599 interface = interface->next;
603 /* select port by algorithm */
604 ifport_start = interface->ifport;
606 if (interface->hunt == HUNT_ROUNDROBIN) {
607 while(ifport_start->next && index<interface->hunt_next) {
608 ifport_start = ifport_start->next;
611 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
612 add_trace("port", NULL, "%d", ifport_start->portnum);
613 add_trace("position", NULL, "%d", index);
618 ifport = ifport_start;
621 /* see if port is available */
622 if (!ifport->mISDNport) {
623 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
624 add_trace("port", NULL, "%d", ifport->portnum);
625 add_trace("position", NULL, "%d", index);
629 mISDNport = ifport->mISDNport;
631 /* see if port is administratively blocked */
633 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
634 add_trace("port", NULL, "%d", ifport->portnum);
635 add_trace("position", NULL, "%d", index);
640 /* see if link is up on PTP*/
641 if (mISDNport->l2hold && mISDNport->l2link<1) {
642 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
643 add_trace("port", NULL, "%d", ifport->portnum);
644 add_trace("position", NULL, "%d", index);
649 /* check for channel form selection list */
652 if (mISDNport->ss5) {
654 port = ss5_hunt_line(mISDNport);
656 *channel = port->p_m_b_channel;
657 trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
658 add_trace("port", NULL, "%d", ifport->portnum);
659 add_trace("position", NULL, "%d", index);
660 add_trace("channel", NULL, "%d", *channel);
666 selchannel = ifport->out_channel;
668 switch(selchannel->channel) {
669 case CHANNEL_FREE: /* free channel */
670 if (mISDNport->b_reserved >= mISDNport->b_num)
671 break; /* all channel in use or reserverd */
674 while(i < mISDNport->b_num) {
675 if (mISDNport->b_port[i] == NULL) {
676 *channel = i+1+(i>=15);
677 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
678 add_trace("port", NULL, "%d", ifport->portnum);
679 add_trace("position", NULL, "%d", index);
680 add_trace("channel", NULL, "%d", *channel);
688 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
689 add_trace("port", NULL, "%d", ifport->portnum);
690 add_trace("position", NULL, "%d", index);
694 case CHANNEL_ANY: /* don't ask for channel */
695 if (mISDNport->b_reserved >= mISDNport->b_num) {
696 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
697 add_trace("port", NULL, "%d", ifport->portnum);
698 add_trace("position", NULL, "%d", index);
699 add_trace("total", NULL, "%d", mISDNport->b_num);
700 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
702 break; /* all channel in use or reserverd */
704 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
705 add_trace("port", NULL, "%d", ifport->portnum);
706 add_trace("position", NULL, "%d", index);
708 *channel = CHANNEL_ANY;
711 case CHANNEL_NO: /* call waiting */
712 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
713 add_trace("port", NULL, "%d", ifport->portnum);
714 add_trace("position", NULL, "%d", index);
716 *channel = CHANNEL_NO;
720 if (selchannel->channel<1 || selchannel->channel==16) {
721 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
722 add_trace("port", NULL, "%d", ifport->portnum);
723 add_trace("position", NULL, "%d", index);
724 add_trace("channel", NULL, "%d", selchannel->channel);
726 break; /* invalid channels */
728 i = selchannel->channel-1-(selchannel->channel>=17);
729 if (i >= mISDNport->b_num) {
730 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
731 add_trace("port", NULL, "%d", ifport->portnum);
732 add_trace("position", NULL, "%d", index);
733 add_trace("channel", NULL, "%d", selchannel->channel);
734 add_trace("channels", NULL, "%d", mISDNport->b_num);
736 break; /* channel not in port */
738 if (mISDNport->b_port[i] == NULL) {
739 *channel = selchannel->channel;
740 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
741 add_trace("port", NULL, "%d", ifport->portnum);
742 add_trace("position", NULL, "%d", index);
743 add_trace("channel", NULL, "%d", *channel);
750 break; /* found channel */
751 selchannel = selchannel->next;
755 /* if channel was found, return mISDNport and channel */
757 /* setting next port to start next time */
758 if (interface->hunt == HUNT_ROUNDROBIN) {
762 interface->hunt_next = index;
768 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
769 add_trace("port", NULL, "%d", ifport->portnum);
770 add_trace("position", NULL, "%d", index);
774 /* go next port, until all ports are checked */
776 ifport = ifport->next;
779 ifport = interface->ifport;
781 if (ifport != ifport_start)
785 interface = interface->next;
789 return(NULL); /* no port found */
792 /* outgoing setup to port(s)
793 * ports will be created and a setup is sent if everything is ok. otherwhise
794 * the endpoint is destroyed.
796 void EndpointAppPBX::out_setup(void)
798 struct dialing_info dialinginfo;
800 struct port_list *portlist;
801 struct lcr_msg *message;
803 int cause = CAUSE_RESSOURCEUNAVAIL;
806 struct mISDNport *mISDNport;
809 class EndpointAppPBX *atemp;
810 // char allowed_ports[256];
812 char ifname[sizeof(e_ext.interfaces)],
814 struct port_settings port_settings;
817 int mode = B_MODE_TRANSPARENT;
819 /* set bchannel mode */
820 mode = e_capainfo.source_mode;
822 /* create settings for creating port */
823 memset(&port_settings, 0, sizeof(port_settings));
825 SCPY(port_settings.tones_dir, e_ext.tones_dir);
827 SCPY(port_settings.tones_dir, options.tones_dir);
828 port_settings.no_seconds = e_ext.no_seconds;
830 /* 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 */
832 /* check what dialinginfo.itype we got */
833 switch(e_dialinginfo.itype) {
834 /* *********************** call to extension or vbox */
835 case INFO_ITYPE_ISDN_EXTENSION:
836 /* check if we deny incoming calls when we use an extension */
837 if (e_ext.noknocking) {
838 atemp = apppbx_first;
841 if (!strcmp(atemp->e_ext.number, e_ext.number))
846 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
847 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYSPE_ join, port */
848 return; /* must exit here */
851 /* FALL THROUGH !!!! */
852 case INFO_ITYPE_VBOX:
853 /* get dialed extension's info */
854 // SCPY(exten, e_dialinginfo.id);
855 // if (strchr(exten, ','))
856 // *strchr(exten, ',') = '\0';
857 // if (!read_extension(&e_ext, exten))
858 if (!read_extension(&e_ext, e_dialinginfo.id)) {
859 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
860 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
861 return; /* must exit here */
864 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
865 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
870 /* string from unconditional call forward (cfu) */
873 /* present to forwarded party */
874 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
875 e_callerinfo.present = INFO_PRESENT_ALLOWED;
877 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
881 /* string from busy call forward (cfb) */
884 class EndpointAppPBX *checkapp = apppbx_first;
886 if (checkapp != this) { /* any other endpoint except our own */
887 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
888 /* present to forwarded party */
889 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
890 e_callerinfo.present = INFO_PRESENT_ALLOWED;
892 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
896 checkapp = checkapp->next;
900 /* string from no-response call forward (cfnr) */
903 /* when cfnr is done, out_setup() will setup the call */
905 /* present to forwarded party */
906 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
907 e_callerinfo.present = INFO_PRESENT_ALLOWED;
911 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
912 e_cfnr_release = now + e_ext.cfnr_delay;
913 e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */
914 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);
918 /* call to all internal interfaces */
919 p = e_ext.interfaces;
920 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
923 while(*p!=',' && *p!='\0')
928 /* found interface */
929 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
930 /* hunt for mISDNport and create Port */
931 mISDNport = hunt_port(ifname, &channel);
933 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
934 add_trace("interface", NULL, "%s", ifname);
938 /* creating INTERNAL port */
939 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
942 port = ss5_hunt_line(mISDNport);
946 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);
949 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
954 FATAL("No memory for Port instance\n");
955 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
956 memset(&dialinginfo, 0, sizeof(dialinginfo));
957 SCPY(dialinginfo.id, e_dialinginfo.id);
958 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
959 dialinginfo.ntype = e_dialinginfo.ntype;
960 /* create port_list relation */
961 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
963 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
965 goto check_anycall_intern;
968 if (e_callerinfo.id[0] && e_ext.display_name) {
969 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
971 SCPY(e_callerinfo.name, dirname);
973 // dss1 = (class Pdss1 *)port;
975 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
976 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
977 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
978 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
979 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
980 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
981 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
982 //terminal if (e_dialinginfo.id)
983 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
984 /* handle restricted caller ids */
985 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);
986 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);
987 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);
988 /* display callerid if desired for extension */
989 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));
990 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
991 /* use cnip, if enabld */
992 // if (!e_ext.centrex)
993 // message->param.setup.callerinfo.name[0] = '\0';
994 /* screen clip if prefix is required */
995 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
996 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
997 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
998 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1000 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1001 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1002 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1003 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1005 /* use internal caller id */
1006 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1007 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1008 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1009 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1011 message_put(message);
1012 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1016 /* string from parallel call forward (cfp) */
1019 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1020 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1021 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1025 vbox_only: /* entry point for answering machine only */
1026 cfu_only: /* entry point for cfu */
1027 cfb_only: /* entry point for cfb */
1028 cfnr_only: /* entry point for cfnr */
1029 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1033 /* only if vbox should be dialed, and terminal is given */
1034 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1035 /* go to the end of p */
1038 /* answering vbox call */
1039 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1041 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1042 FATAL("No memory for VBOX Port instance\n");
1043 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1044 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1047 while(*p!=',' && *p!='\0')
1052 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1053 /* hunt for mISDNport and create Port */
1054 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1056 /* creating EXTERNAL port*/
1057 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1060 port = ss5_hunt_line(mISDNport);
1063 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);
1065 FATAL("No memory for Port instance\n");
1066 earlyb = mISDNport->earlyb;
1069 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1070 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1075 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1076 goto check_anycall_intern;
1078 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1079 memset(&dialinginfo, 0, sizeof(dialinginfo));
1080 SCPY(dialinginfo.id, cfp);
1081 dialinginfo.itype = INFO_ITYPE_ISDN;
1082 dialinginfo.ntype = e_dialinginfo.ntype;
1083 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1085 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1087 goto check_anycall_intern;
1089 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1090 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1091 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1092 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1093 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1094 /* if clip is hidden */
1095 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1096 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1097 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1098 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1099 message->param.setup.callerinfo.present = e_ext.callerid_present;
1100 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1102 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1103 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1104 //terminal if (e_dialinginfo.id)
1105 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1106 /* handle restricted caller ids */
1107 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);
1108 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);
1109 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);
1110 /* display callerid if desired for extension */
1111 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));
1112 message_put(message);
1113 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1117 check_anycall_intern:
1118 /* now we have all ports created */
1120 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1122 if (!ea_endpoint->ep_join_id)
1124 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1125 return; /* must exit here */
1129 /* *********************** external call */
1131 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1132 /* call to extenal interfaces */
1133 if (e_dialinginfo.keypad[0])
1134 p = e_dialinginfo.keypad;
1136 p = e_dialinginfo.id;
1139 while(*p!=',' && *p!='\0')
1140 SCCAT(number, *p++);
1144 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");
1145 /* hunt for mISDNport and create Port */
1146 /* hunt for mISDNport and create Port */
1147 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1149 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1150 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1152 goto check_anycall_extern;
1154 /* creating EXTERNAL port*/
1155 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1158 port = ss5_hunt_line(mISDNport);
1161 if (!mISDNport->gsm)
1162 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);
1165 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1170 FATAL("No memory for Port instance\n");
1171 earlyb = mISDNport->earlyb;
1172 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1173 memset(&dialinginfo, 0, sizeof(dialinginfo));
1174 if (e_dialinginfo.keypad[0])
1175 SCPY(dialinginfo.keypad, number);
1177 SCPY(dialinginfo.id, number);
1178 dialinginfo.itype = INFO_ITYPE_ISDN;
1179 dialinginfo.ntype = e_dialinginfo.ntype;
1180 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1182 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1184 goto check_anycall_extern;
1186 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1187 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1188 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1189 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1190 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1191 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1192 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1193 //terminal if (e_dialinginfo.id)
1194 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1195 /* handle restricted caller ids */
1196 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);
1197 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);
1198 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);
1199 /* display callerid if desired for extension */
1200 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));
1201 message_put(message);
1202 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1206 check_anycall_extern:
1207 /* now we have all ports created */
1209 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1211 if (!ea_endpoint->ep_join_id)
1213 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1214 return; /* must exit here */
1222 /* handler for endpoint
1226 int EndpointAppPBX::handler(void)
1228 if (e_crypt_state!=CM_ST_NULL) {
1232 /* process answering machine (play) handling */
1234 if (e_action->index == ACTION_VBOX_PLAY)
1237 /* process action timeout */
1238 if (e_action_timeout)
1239 if (now_d >= e_action_timeout) {
1240 if (e_state!=EPOINT_STATE_CONNECT) {
1242 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea_endpoint->ep_serial);
1243 e_multipoint_cause = 0;
1244 e_multipoint_location = 0;
1245 new_state(EPOINT_STATE_IN_OVERLAP);
1248 return(1); /* we must exit, because our endpoint might be gone */
1250 e_action_timeout = 0;
1253 /* process action timeout */
1254 if (e_match_timeout)
1255 if (now_d >= e_match_timeout) {
1257 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea_endpoint->ep_serial);
1259 return(1); /* we must exit, because our endpoint might be gone */
1264 /* process redialing (epoint redials to port) */
1266 if (now_d >= e_redial) {
1268 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea_endpoint->ep_serial);
1270 new_state(EPOINT_STATE_OUT_SETUP);
1271 /* call special setup routine */
1278 /* process powerdialing (epoint redials to epoint) */
1279 if (e_powerdialing > 0) {
1280 if (now_d >= e_powerdialing) {
1281 e_powerdialing = -1; /* leave power dialing on */
1282 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea_endpoint->ep_serial);
1285 e_ruleset = ruleset_main;
1287 e_rule = e_ruleset->rule_first;
1289 new_state(EPOINT_STATE_IN_OVERLAP);
1295 /* process call forward no response */
1296 if (e_cfnr_release) {
1297 struct port_list *portlist;
1298 struct lcr_msg *message;
1300 if (now >= e_cfnr_release) {
1301 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea_endpoint->ep_serial);
1304 /* release all ports */
1305 while((portlist = ea_endpoint->ep_portlist)) {
1306 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1307 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1308 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1309 message_put(message);
1310 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1311 ea_endpoint->free_portlist(portlist);
1314 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1315 message->param.audiopath = 0;
1316 message_put(message);
1317 /* indicate no patterns */
1318 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1319 message_put(message);
1320 /* set setup state, since we have no response from the new join */
1321 new_state(EPOINT_STATE_OUT_SETUP);
1325 if (now >= e_cfnr_call) {
1326 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea_endpoint->ep_serial, e_ext.cfnr);
1332 /* handle connection to user */
1333 if (e_state == EPOINT_STATE_IDLE) {
1334 /* epoint is idle, check callback */
1336 if (now_d >= e_callback) {
1337 e_callback = 0; /* done with callback */
1338 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea_endpoint->ep_serial);
1339 new_state(EPOINT_STATE_OUT_SETUP);
1345 /* check for password timeout */
1347 if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE) {
1348 struct port_list *portlist;
1350 if (now >= e_password_timeout) {
1351 e_ruleset = ruleset_main;
1353 e_rule = e_ruleset->rule_first;
1355 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea_endpoint->ep_serial, e_extdialing);
1356 trace_header("PASSWORD timeout", DIRECTION_NONE);
1358 e_connectedmode = 0;
1360 new_state(EPOINT_STATE_OUT_DISCONNECT);
1361 portlist = ea_endpoint->ep_portlist;
1363 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1364 set_tone(portlist, "cause_10");
1374 /* doing a hookflash */
1375 void EndpointAppPBX::hookflash(void)
1379 /* be sure that we are active */
1381 e_tx_state = NOTIFY_STATE_ACTIVE;
1383 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1385 if (ea_endpoint->ep_use > 1) {
1386 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1389 /* dialtone after pressing the hash key */
1390 process_hangup(e_join_cause, e_join_location);
1391 e_multipoint_cause = 0;
1392 e_multipoint_location = 0;
1393 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1395 port->set_echotest(0);
1397 if (ea_endpoint->ep_join_id) {
1398 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1400 e_ruleset = ruleset_main;
1402 e_rule = e_ruleset->rule_first;
1404 new_state(EPOINT_STATE_IN_OVERLAP);
1405 e_connectedmode = 1;
1406 SCPY(e_dialinginfo.id, e_ext.prefix);
1407 e_extdialing = e_dialinginfo.id;
1409 if (e_dialinginfo.id[0]) {
1410 set_tone(ea_endpoint->ep_portlist, "dialing");
1413 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1420 /* messages from port
1422 /* port MESSAGE_SETUP */
1423 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1425 struct lcr_msg *message;
1427 int writeext; /* flags need to write extension after modification */
1429 struct interface *interface;
1431 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1433 portlist->port_type = param->setup.port_type;
1434 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1435 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1436 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1437 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1439 /* convert (inter-)national number type */
1440 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1441 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1443 // e_dtmf = param->setup.dtmf;
1444 /* screen incoming caller id */
1445 interface = interface_first;
1447 if (!strcmp(e_callerinfo.interface, interface->name)) {
1450 interface = interface->next;
1453 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1454 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1457 /* process extension */
1458 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1459 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1460 /* port makes call from extension */
1461 SCPY(e_callerinfo.extension, e_callerinfo.id);
1462 SCPY(e_ext.number, e_callerinfo.extension);
1463 SCPY(e_extension_interface, e_callerinfo.interface);
1465 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1468 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1469 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1471 /* get extension's info about caller */
1472 if (!read_extension(&e_ext, e_ext.number)) {
1473 /* extension doesn't exist */
1474 trace_header("EXTENSION (not created)", DIRECTION_IN);
1475 add_trace("extension", NULL, "%s", e_ext.number);
1477 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1478 new_state(EPOINT_STATE_OUT_DISCONNECT);
1479 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1480 e_ext.number[0] = '\0'; /* no terminal */
1485 /* put prefix (next) in front of e_dialinginfo.id */
1486 if (e_ext.next[0]) {
1487 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1488 SCPY(e_dialinginfo.id, buffer);
1489 e_ext.next[0] = '\0';
1491 } else if (e_ext.prefix[0]) {
1492 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1493 SCPY(e_dialinginfo.id, buffer);
1496 /* screen caller id by extension's config */
1497 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1499 SCPY(e_callerinfo.name, e_ext.name);
1500 /* use caller id (or if exist: id_next_call) for this call */
1501 if (e_ext.id_next_call_present >= 0) {
1502 SCPY(e_callerinfo.id, e_ext.id_next_call);
1503 /* if we restrict the pesentation */
1504 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1505 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1506 else e_callerinfo.present = e_ext.id_next_call_present;
1507 e_callerinfo.ntype = e_ext.id_next_call_type;
1508 e_ext.id_next_call_present = -1;
1511 SCPY(e_callerinfo.id, e_ext.callerid);
1512 /* if we restrict the pesentation */
1513 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1514 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1515 else e_callerinfo.present = e_ext.callerid_present;
1516 e_callerinfo.ntype = e_ext.callerid_type;
1518 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1520 /* extension is written */
1522 write_extension(&e_ext, e_ext.number);
1524 /* set volume of rx and tx */
1525 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1526 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1527 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1528 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1529 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1530 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1531 message_put(message);
1534 /* start recording if enabled */
1535 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1536 /* check if we are a terminal */
1537 if (e_ext.number[0] == '\0')
1538 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1540 port = find_port_id(portlist->port_id);
1542 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1546 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1547 /* no terminal identification */
1548 e_ext.number[0] = '\0';
1549 e_extension_interface[0] = '\0';
1550 memset(&e_ext, 0, sizeof(e_ext));
1551 e_ext.rights = 4; /* right to dial internat */
1555 e_ruleset = ruleset_main;
1557 e_rule = e_ruleset->rule_first;
1559 e_extdialing = e_dialinginfo.id;
1560 new_state(EPOINT_STATE_IN_SETUP);
1561 if (e_dialinginfo.id[0]) {
1562 set_tone(portlist, "dialing");
1564 if (e_ext.number[0])
1565 set_tone(portlist, "dialpbx");
1567 set_tone(portlist, "dialtone");
1570 if (e_state == EPOINT_STATE_IN_SETUP) {
1571 /* request MORE info, if not already at higher state */
1572 new_state(EPOINT_STATE_IN_OVERLAP);
1573 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1574 message_put(message);
1575 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1579 /* port MESSAGE_INFORMATION */
1580 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1582 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1584 /* ignore information message without digit information */
1585 if (!param->information.id[0])
1590 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1592 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1597 /* if vbox_play is done, the information are just used as they come */
1599 if (e_action->index == ACTION_VBOX_PLAY) {
1600 /* concat dialing string */
1601 SCAT(e_dialinginfo.id, param->information.id);
1606 /* keypad when disconnect but in connected mode */
1607 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1608 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1609 /* processing keypad function */
1610 if (param->information.id[0] == '0') {
1616 /* keypad when connected */
1617 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1618 if (e_ext.keypad || e_enablekeypad) {
1619 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1620 /* processing keypad function */
1621 if (param->information.id[0] == '0') {
1624 if (param->information.id[0])
1625 keypad_function(param->information.id[0]);
1627 if (e_ext.number[0])
1628 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1630 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1635 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1636 if (e_ext.number[0])
1637 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1639 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1643 if (!param->information.id[0])
1645 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1646 set_tone(portlist, "dialing");
1649 if (e_action->index==ACTION_OUTDIAL
1650 || e_action->index==ACTION_EXTERNAL
1651 || e_action->index==ACTION_REMOTE) {
1653 set_tone(portlist, "dialing");
1654 else if (!e_extdialing[0])
1655 set_tone(portlist, "dialing");
1657 /* concat dialing string */
1658 SCAT(e_dialinginfo.id, param->information.id);
1662 /* port MESSAGE_DTMF */
1663 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1665 /* only if dtmf detection is enabled */
1667 trace_header("DTMF (disabled)", DIRECTION_IN);
1671 trace_header("DTMF", DIRECTION_IN);
1672 add_trace("digit", NULL, "%c", param->dtmf);
1676 NOTE: vbox is now handled due to overlap state
1677 /* if vbox_play is done, the dtmf digits are just used as they come */
1679 if (e_action->index == ACTION_VBOX_PLAY) {
1680 /* concat dialing string */
1681 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1682 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1683 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1686 /* continue to process *X# sequences */
1690 /* check for *X# sequence */
1691 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1692 if (e_dtmf_time+3 < now) {
1693 /* the last digit was too far in the past to be a sequence */
1694 if (param->dtmf == '*')
1695 /* only start is allowed in the sequence */
1700 /* we have a sequence of digits, see what we got */
1701 if (param->dtmf == '*')
1703 else if (param->dtmf>='0' && param->dtmf<='9') {
1704 /* we need to have a star before we receive the digit of the sequence */
1705 if (e_dtmf_last == '*')
1706 e_dtmf_last = param->dtmf;
1707 } else if (param->dtmf == '#') {
1709 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1710 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1711 if (e_dtmf_last == '0') {
1715 /* processing keypad function */
1717 keypad_function(e_dtmf_last);
1723 /* set last time of dtmf */
1728 /* check for ## hookflash during dialing */
1730 if (e_action->index==ACTION_PASSWORD
1731 || e_action->index==ACTION_PASSWORD_WRITE)
1733 if (param->dtmf=='#') { /* current digit is '#' */
1734 if (e_state==EPOINT_STATE_IN_DISCONNECT
1735 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1749 /* dialing using dtmf digit */
1750 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1751 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1752 set_tone(portlist, "dialing");
1754 /* concat dialing string */
1755 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1756 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1757 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1763 /* port MESSAGE_CRYPT */
1764 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1766 /* send crypt response to cryptman */
1767 if (param->crypt.type == CR_MESSAGE_IND)
1768 cryptman_msg2man(param->crypt.data, param->crypt.len);
1770 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1773 /* port MESSAGE_OVERLAP */
1774 void EndpointAppPBX::port_overlap(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_SETUP_ACK, "", 0, 0, 0);
1783 if (e_dialing_queue[0] && portlist) {
1784 /* send what we have not dialed yet, because we had no setup complete */
1785 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1786 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1787 SCPY(message->param.information.id, e_dialing_queue);
1788 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1789 message_put(message);
1790 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1791 e_dialing_queue[0] = '\0';
1793 /* check if pattern is available */
1794 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1795 /* indicate patterns */
1796 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1797 message_put(message);
1799 /* connect 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 = 1;
1802 message_put(message);
1804 /* indicate no patterns */
1805 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1806 message_put(message);
1808 /* disconnect audio, if not already */
1809 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1810 message->param.audiopath = 0;
1811 message_put(message);
1813 new_state(EPOINT_STATE_OUT_OVERLAP);
1814 /* if we are in a join */
1815 if (ea_endpoint->ep_join_id) {
1816 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1817 memcpy(&message->param, param, sizeof(union parameter));
1818 message_put(message);
1822 /* port MESSAGE_PROCEEDING */
1823 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1825 struct lcr_msg *message;
1827 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1829 /* signal to call tool */
1830 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1832 e_state = EPOINT_STATE_OUT_PROCEEDING;
1833 /* check if pattern is availatle */
1834 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1835 /* indicate patterns */
1836 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1837 message_put(message);
1839 /* connect audio, if not already */
1840 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1841 message->param.audiopath = 1;
1842 message_put(message);
1844 /* indicate no patterns */
1845 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1846 message_put(message);
1848 /* disconnect audio, if not already */
1849 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1850 message->param.audiopath = 0;
1851 message_put(message);
1853 /* if we are in a call */
1854 if (ea_endpoint->ep_join_id) {
1855 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1856 memcpy(&message->param, param, sizeof(union parameter));
1857 message_put(message);
1861 /* port MESSAGE_ALERTING */
1862 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1864 struct lcr_msg *message;
1866 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1868 /* signal to call tool */
1869 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1872 // set_tone(portlist, "hold");
1874 new_state(EPOINT_STATE_OUT_ALERTING);
1875 /* check if pattern is available */
1876 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1877 /* indicate patterns */
1878 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1879 message_put(message);
1881 /* connect audio, if not already */
1882 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1883 message->param.audiopath = 1;
1884 message_put(message);
1886 /* indicate no patterns */
1887 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1888 message_put(message);
1890 /* disconnect audio, if not already */
1891 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1892 message->param.audiopath = 0;
1893 message_put(message);
1895 /* if we are in a call */
1896 if (ea_endpoint->ep_join_id) {
1897 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1898 memcpy(&message->param, param, sizeof(union parameter));
1899 message_put(message);
1903 /* port MESSAGE_CONNECT */
1904 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1906 struct lcr_msg *message;
1908 unsigned int port_id = portlist->port_id;
1909 struct port_list *tportlist;
1911 struct interface *interface;
1913 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1915 /* signal to call tool */
1916 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1918 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1919 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1920 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1921 tportlist = ea_endpoint->ep_portlist;
1922 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1923 tportlist = tportlist->next;
1924 if (tportlist->port_id == port_id)
1925 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1926 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1927 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1928 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1929 message_put(message);
1930 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1931 ea_endpoint->free_portlist(tportlist);
1933 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1937 /* screen incoming connected id */
1938 interface = interface_first;
1940 if (!strcmp(e_connectinfo.interface, interface->name)) {
1943 interface = interface->next;
1946 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1948 /* screen connected name */
1950 SCPY(e_connectinfo.name, e_ext.name);
1952 /* add internal id to colp */
1953 SCPY(e_connectinfo.extension, e_ext.number);
1955 /* we store the connected port number */
1956 SCPY(e_extension_interface, e_connectinfo.interface);
1958 /* for internal and am calls, we get the extension's id */
1959 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1960 SCPY(e_connectinfo.id, e_ext.callerid);
1961 SCPY(e_connectinfo.extension, e_ext.number);
1962 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1963 e_connectinfo.ntype = e_ext.callerid_type;
1964 e_connectinfo.present = e_ext.callerid_present;
1966 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
1967 e_connectinfo.itype = INFO_ITYPE_VBOX;
1968 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1971 new_state(EPOINT_STATE_CONNECT);
1973 /* set volume of rx and tx */
1974 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1975 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1976 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1977 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1978 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1979 message_put(message);
1982 e_cfnr_call = e_cfnr_release = 0;
1983 if (e_ext.number[0])
1984 e_dtmf = 1; /* allow dtmf */
1987 /* other calls with no caller id (or not available for the extension) and force colp */
1988 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
1989 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
1990 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 */
1991 port = find_port_id(portlist->port_id);
1993 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
1994 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1999 /* send connect to join */
2000 if (ea_endpoint->ep_join_id) {
2001 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2002 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2003 message_put(message);
2005 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2006 message->param.audiopath = 1;
2007 message_put(message);
2008 } else if (!e_adminid) {
2010 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2011 SCPY(e_ext.number, e_cbcaller);
2012 new_state(EPOINT_STATE_IN_OVERLAP);
2013 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2015 /* get extension's info about terminal */
2016 if (!read_extension(&e_ext, e_ext.number)) {
2017 /* extension doesn't exist */
2018 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2019 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2020 new_state(EPOINT_STATE_OUT_DISCONNECT);
2021 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2025 /* put prefix in front of e_cbdialing */
2026 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2027 SCPY(e_dialinginfo.id, buffer);
2028 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2029 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2031 /* use caller id (or if exist: id_next_call) for this call */
2032 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2033 SCPY(e_callerinfo.extension, e_ext.number);
2034 if (e_ext.id_next_call_present >= 0) {
2035 SCPY(e_callerinfo.id, e_ext.id_next_call);
2036 e_callerinfo.present = e_ext.id_next_call_present;
2037 e_callerinfo.ntype = e_ext.id_next_call_type;
2038 e_ext.id_next_call_present = -1;
2039 /* extension is written */
2040 write_extension(&e_ext, e_ext.number);
2042 SCPY(e_callerinfo.id, e_ext.callerid);
2043 e_callerinfo.present = e_ext.callerid_present;
2044 e_callerinfo.ntype = e_ext.callerid_type;
2046 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2048 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2051 /* check if caller id is NOT authenticated */
2052 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2053 /* make call state to enter password */
2054 new_state(EPOINT_STATE_IN_OVERLAP);
2055 e_action = &action_password_write;
2056 e_match_timeout = 0;
2057 e_match_to_action = NULL;
2058 e_dialinginfo.id[0] = '\0';
2059 e_extdialing = strchr(e_dialinginfo.id, '\0');
2060 e_password_timeout = now+20;
2063 /* incoming call (callback) */
2064 e_ruleset = ruleset_main;
2066 e_rule = e_ruleset->rule_first;
2068 e_extdialing = e_dialinginfo.id;
2069 if (e_dialinginfo.id[0]) {
2070 set_tone(portlist, "dialing");
2073 set_tone(portlist, "dialpbx");
2076 } else { /* testcall */
2077 set_tone(portlist, "hold");
2080 /* start recording if enabled, not when answering machine answers */
2081 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)) {
2082 /* check if we are a terminal */
2083 if (e_ext.number[0] == '\0')
2084 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2086 port = find_port_id(portlist->port_id);
2088 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2093 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2094 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2096 struct lcr_msg *message;
2098 unsigned int port_id = portlist->port_id;
2102 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2104 /* signal to call tool */
2105 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2107 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2108 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2109 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2114 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);
2115 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2116 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2118 /* check if we have more than one portlist relation and we just ignore the disconnect */
2119 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2120 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2121 portlist = ea_endpoint->ep_portlist;
2123 if (portlist->port_id == port_id)
2125 portlist = portlist->next;
2128 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2129 if (message_type != MESSAGE_RELEASE) {
2130 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2131 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2132 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2133 message_put(message);
2134 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2136 ea_endpoint->free_portlist(portlist);
2137 return; /* one relation removed */
2139 if (e_state == EPOINT_STATE_CONNECT) {
2140 /* use cause from port after connect */
2141 cause = param->disconnectinfo.cause;
2142 location = param->disconnectinfo.location;
2144 /* use multipoint cause if no connect yet */
2145 if (e_multipoint_cause) {
2146 cause = e_multipoint_cause;
2147 location = e_multipoint_location;
2149 cause = CAUSE_NOUSER;
2150 location = LOCATION_PRIVATE_LOCAL;
2154 e_cfnr_call = e_cfnr_release = 0;
2156 /* process hangup */
2157 process_hangup(e_join_cause, e_join_location);
2158 e_multipoint_cause = 0;
2159 e_multipoint_location = 0;
2161 if (message_type == MESSAGE_DISCONNECT) {
2162 /* tone to disconnected end */
2163 SPRINT(buffer, "cause_%02x", cause);
2164 if (ea_endpoint->ep_portlist)
2165 set_tone(ea_endpoint->ep_portlist, buffer);
2167 new_state(EPOINT_STATE_IN_DISCONNECT);
2170 if (ea_endpoint->ep_join_id) {
2171 int haspatterns = 0;
2172 /* check if pattern is available */
2173 if (ea_endpoint->ep_portlist)
2174 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2175 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
2176 && message_type != MESSAGE_RELEASE) // if we release, we are done
2179 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2180 /* indicate patterns */
2181 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2182 message_put(message);
2183 /* connect audio, if not already */
2184 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2185 message->param.audiopath = 1;
2186 message_put(message);
2187 /* send disconnect */
2188 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2189 memcpy(&message->param, param, sizeof(union parameter));
2190 message_put(message);
2191 /* disable encryption if disconnected */
2192 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2194 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2197 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2200 if (message_type == MESSAGE_RELEASE)
2201 ea_endpoint->free_portlist(portlist);
2202 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */
2203 return; /* must exit here */
2206 /* port MESSAGE_TIMEOUT */
2207 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2211 trace_header("TIMEOUT", DIRECTION_IN);
2212 message_type = MESSAGE_DISCONNECT;
2213 switch (param->state) {
2214 case PORT_STATE_OUT_SETUP:
2215 case PORT_STATE_OUT_OVERLAP:
2216 add_trace("state", NULL, "outgoing setup/dialing");
2218 /* no user responding */
2219 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2220 return; /* must exit here */
2222 case PORT_STATE_IN_SETUP:
2223 case PORT_STATE_IN_OVERLAP:
2224 add_trace("state", NULL, "incoming setup/dialing");
2225 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2226 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2229 case PORT_STATE_OUT_PROCEEDING:
2230 add_trace("state", NULL, "outgoing proceeding");
2232 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2233 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2234 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2235 return; /* must exit here */
2237 case PORT_STATE_IN_PROCEEDING:
2238 add_trace("state", NULL, "incoming proceeding");
2239 param->disconnectinfo.cause = CAUSE_NOUSER;
2240 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2243 case PORT_STATE_OUT_ALERTING:
2244 add_trace("state", NULL, "outgoing alerting");
2246 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2247 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2248 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2249 return; /* must exit here */
2251 case PORT_STATE_CONNECT:
2252 add_trace("state", NULL, "connect");
2254 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2255 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2256 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2257 return; /* must exit here */
2259 case PORT_STATE_IN_ALERTING:
2260 add_trace("state", NULL, "incoming alerting");
2261 param->disconnectinfo.cause = CAUSE_NOANSWER;
2262 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2265 case PORT_STATE_IN_DISCONNECT:
2266 case PORT_STATE_OUT_DISCONNECT:
2267 add_trace("state", NULL, "disconnect");
2269 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2270 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2271 return; /* must exit here */
2274 param->disconnectinfo.cause = 31; /* normal unspecified */
2275 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2278 /* release call, disconnect isdn */
2280 new_state(EPOINT_STATE_OUT_DISCONNECT);
2281 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2282 SCPY(e_tone, cause);
2284 set_tone(portlist, cause);
2285 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2286 portlist = portlist->next;
2288 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2291 /* port MESSAGE_NOTIFY */
2292 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2294 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2296 struct lcr_msg *message;
2297 const char *logtext = "";
2300 /* signal to call tool */
2301 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);
2302 if (param->notifyinfo.notify) {
2303 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2306 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2307 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2308 case INFO_NOTIFY_REMOTE_HOLD:
2309 case INFO_NOTIFY_USER_SUSPENDED:
2310 /* tell call about it */
2311 if (ea_endpoint->ep_join_id) {
2312 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2313 message->param.audiopath = 0;
2314 message_put(message);
2318 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2319 case INFO_NOTIFY_USER_RESUMED:
2320 /* set volume of rx and tx */
2321 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2322 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2324 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2325 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2326 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2327 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2328 message_put(message);
2330 /* set current tone */
2332 set_tone(portlist, e_tone);
2333 /* tell call about it */
2334 if (ea_endpoint->ep_join_id) {
2335 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2336 message->param.audiopath = 1;
2337 message_put(message);
2342 /* get name of notify */
2343 switch(param->notifyinfo.notify) {
2348 logtext = "USER_SUSPENDED";
2351 logtext = "BEARER_SERVICE_CHANGED";
2354 logtext = "USER_RESUMED";
2357 logtext = "CONFERENCE_ESTABLISHED";
2360 logtext = "CONFERENCE_DISCONNECTED";
2363 logtext = "OTHER_PARTY_ADDED";
2366 logtext = "ISOLATED";
2369 logtext = "REATTACHED";
2372 logtext = "OTHER_PARTY_ISOLATED";
2375 logtext = "OTHER_PARTY_REATTACHED";
2378 logtext = "OTHER_PARTY_SPLIT";
2381 logtext = "OTHER_PARTY_DISCONNECTED";
2384 logtext = "CONFERENCE_FLOATING";
2387 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2390 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2393 logtext = "CALL_IS_A_WAITING_CALL";
2396 logtext = "DIVERSION_ACTIVATED";
2399 logtext = "RESERVED_CT_1";
2402 logtext = "RESERVED_CT_2";
2405 logtext = "REVERSE_CHARGING";
2408 logtext = "REMOTE_HOLD";
2411 logtext = "REMOTE_RETRIEVAL";
2414 logtext = "CALL_IS_DIVERTING";
2417 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2422 /* notify call if available */
2423 if (ea_endpoint->ep_join_id) {
2424 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2425 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2426 message_put(message);
2431 /* port MESSAGE_FACILITY */
2432 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2434 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2436 struct lcr_msg *message;
2438 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2439 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2440 message_put(message);
2443 /* port MESSAGE_SUSPEND */
2444 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2445 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2447 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2449 /* epoint is now parked */
2450 ea_endpoint->ep_park = 1;
2451 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2452 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2454 /* remove port relation */
2455 ea_endpoint->free_portlist(portlist);
2458 /* port MESSAGE_RESUME */
2459 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2460 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2462 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2464 /* epoint is now resumed */
2465 ea_endpoint->ep_park = 0;
2470 /* port sends message to the endpoint
2472 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2474 struct port_list *portlist;
2476 portlist = ea_endpoint->ep_portlist;
2478 if (port_id == portlist->port_id)
2480 portlist = portlist->next;
2483 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);
2487 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2488 switch(message_type) {
2489 case MESSAGE_DATA: /* data from port */
2490 /* check if there is a call */
2491 if (!ea_endpoint->ep_join_id)
2493 /* continue if only one portlist */
2494 if (ea_endpoint->ep_portlist->next != NULL)
2496 /* forward message */
2497 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2500 case MESSAGE_TONE_EOF: /* tone is end of file */
2501 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2503 if (e_action->index == ACTION_VBOX_PLAY) {
2506 if (e_action->index == ACTION_EFI) {
2512 case MESSAGE_TONE_COUNTER: /* counter info received */
2513 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);
2515 if (e_action->index == ACTION_VBOX_PLAY) {
2516 e_vbox_counter = param->counter.current;
2517 if (param->counter.max >= 0)
2518 e_vbox_counter_max = param->counter.max;
2522 /* PORT sends SETUP message */
2524 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);
2525 if (e_state!=EPOINT_STATE_IDLE) {
2526 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2529 port_setup(portlist, message_type, param);
2532 /* PORT sends INFORMATION message */
2533 case MESSAGE_INFORMATION: /* additional digits received */
2534 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);
2535 port_information(portlist, message_type, param);
2538 /* PORT sends FACILITY message */
2539 case MESSAGE_FACILITY:
2540 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2541 port_facility(portlist, message_type, param);
2544 /* PORT sends DTMF message */
2545 case MESSAGE_DTMF: /* dtmf digits received */
2546 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);
2547 port_dtmf(portlist, message_type, param);
2550 /* PORT sends CRYPT message */
2551 case MESSAGE_CRYPT: /* crypt response received */
2552 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2553 port_crypt(portlist, message_type, param);
2556 /* PORT sends MORE message */
2557 case MESSAGE_OVERLAP:
2558 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);
2559 if (e_state != EPOINT_STATE_OUT_SETUP) {
2560 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);
2563 port_overlap(portlist, message_type, param);
2566 /* PORT sends PROCEEDING message */
2567 case MESSAGE_PROCEEDING: /* port is proceeding */
2568 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);
2569 if (e_state!=EPOINT_STATE_OUT_SETUP
2570 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2571 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);
2574 port_proceeding(portlist, message_type, param);
2577 /* PORT sends ALERTING message */
2578 case MESSAGE_ALERTING:
2579 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);
2580 if (e_state!=EPOINT_STATE_OUT_SETUP
2581 && e_state!=EPOINT_STATE_OUT_OVERLAP
2582 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2583 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);
2586 port_alerting(portlist, message_type, param);
2589 /* PORT sends CONNECT message */
2590 case MESSAGE_CONNECT:
2591 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);
2592 if (e_state!=EPOINT_STATE_OUT_SETUP
2593 && e_state!=EPOINT_STATE_OUT_OVERLAP
2594 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2595 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2596 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2599 port_connect(portlist, message_type, param);
2602 /* PORT sends DISCONNECT message */
2603 case MESSAGE_DISCONNECT: /* port is disconnected */
2604 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);
2605 port_disconnect_release(portlist, message_type, param);
2608 /* PORT sends a RELEASE message */
2609 case MESSAGE_RELEASE: /* port releases */
2610 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);
2611 /* portlist is release at port_disconnect_release, thanx Paul */
2612 port_disconnect_release(portlist, message_type, param);
2615 /* PORT sends a TIMEOUT message */
2616 case MESSAGE_TIMEOUT:
2617 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);
2618 port_timeout(portlist, message_type, param);
2619 break; /* release */
2621 /* PORT sends a NOTIFY message */
2622 case MESSAGE_NOTIFY:
2623 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);
2624 port_notify(portlist, message_type, param);
2627 /* PORT sends a SUSPEND message */
2628 case MESSAGE_SUSPEND:
2629 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);
2630 port_suspend(portlist, message_type, param);
2631 break; /* suspend */
2633 /* PORT sends a RESUME message */
2634 case MESSAGE_RESUME:
2635 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);
2636 port_resume(portlist, message_type, param);
2640 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2641 /* port assigns bchannel */
2642 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2643 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);
2644 /* only one port is expected to be connected to bchannel */
2645 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2646 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2652 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);
2655 /* Note: this endpoint may be destroyed, so we MUST return */
2659 /* messages from join
2661 /* join MESSAGE_CRYPT */
2662 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2664 switch(param->crypt.type) {
2665 /* message from remote port to "crypt manager" */
2666 case CU_ACTK_REQ: /* activate key-exchange */
2667 case CU_ACTS_REQ: /* activate shared key */
2668 case CU_DACT_REQ: /* deactivate */
2669 case CU_INFO_REQ: /* request last info message */
2670 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2673 /* message from "crypt manager" to user */
2674 case CU_ACTK_CONF: /* key-echange done */
2675 case CU_ACTS_CONF: /* shared key done */
2676 case CU_DACT_CONF: /* deactivated */
2677 case CU_DACT_IND: /* deactivated */
2678 case CU_ERROR_IND: /* receive error message */
2679 case CU_INFO_IND: /* receive info message */
2680 case CU_INFO_CONF: /* receive info message */
2681 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2685 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);
2689 /* join MESSAGE_INFORMATION */
2690 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2692 struct lcr_msg *message;
2697 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2698 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2699 message_put(message);
2700 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2701 portlist = portlist->next;
2705 /* join MESSAGE_FACILITY */
2706 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2708 struct lcr_msg *message;
2710 if (!e_ext.facility && e_ext.number[0]) {
2715 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2716 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2717 message_put(message);
2718 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2719 portlist = portlist->next;
2723 /* join MESSAGE_MORE */
2724 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2726 struct lcr_msg *message;
2728 new_state(EPOINT_STATE_IN_OVERLAP);
2731 if (e_join_pattern && e_ext.own_setup) {
2732 /* disconnect audio */
2733 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2734 message->param.audiopath = 0;
2735 message_put(message);
2737 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2738 if (e_dialinginfo.id[0])
2739 set_tone(portlist, "dialing");
2741 set_tone(portlist, "dialtone");
2744 if (e_dialinginfo.id[0]) {
2745 set_tone(portlist, "dialing");
2747 if (e_ext.number[0])
2748 set_tone(portlist, "dialpbx");
2750 set_tone(portlist, "dialtone");
2754 /* join MESSAGE_PROCEEDING */
2755 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2757 struct lcr_msg *message;
2759 new_state(EPOINT_STATE_IN_PROCEEDING);
2761 /* own proceeding tone */
2762 if (e_join_pattern) {
2763 /* connect / disconnect audio */
2764 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2765 if (e_ext.own_proceeding)
2766 message->param.audiopath = 0;
2768 message->param.audiopath = 1;
2769 message_put(message);
2771 // UCPY(e_join_tone, "proceeding");
2773 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2774 message_put(message);
2775 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2777 set_tone(portlist, "proceeding");
2780 /* join MESSAGE_ALERTING */
2781 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2783 struct lcr_msg *message;
2785 new_state(EPOINT_STATE_IN_ALERTING);
2787 /* own alerting tone */
2788 if (e_join_pattern) {
2789 /* connect / disconnect audio */
2790 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2791 if (e_ext.own_alerting)
2792 message->param.audiopath = 0;
2794 message->param.audiopath = 1;
2795 message_put(message);
2798 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2799 message_put(message);
2800 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2802 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2803 set_tone(portlist, "ringing");
2806 if (e_ext.number[0])
2807 set_tone(portlist, "ringpbx");
2809 set_tone(portlist, "ringing");
2811 if (e_ext.number[0])
2812 e_dtmf = 1; /* allow dtmf */
2815 /* join MESSAGE_CONNECT */
2816 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2818 struct lcr_msg *message;
2820 new_state(EPOINT_STATE_CONNECT);
2821 // UCPY(e_join_tone, "");
2823 if (e_ext.number[0])
2824 e_dtmf = 1; /* allow dtmf */
2827 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2829 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2830 memcpy(&message->param, param, sizeof(union parameter));
2832 /* screen clip if prefix is required */
2833 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2834 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2835 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2836 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2839 /* use internal caller id */
2840 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2841 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2842 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2845 /* handle restricted caller ids */
2846 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);
2847 /* display callerid if desired for extension */
2848 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));
2850 /* use conp, if enabld */
2851 // if (!e_ext.centrex)
2852 // message->param.connectinfo.name[0] = '\0';
2855 message_put(message);
2856 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2858 set_tone(portlist, NULL);
2860 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2861 message->param.audiopath = 1;
2862 message_put(message);
2866 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2867 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2870 struct lcr_msg *message;
2871 struct port_list *portlist = NULL;
2874 /* be sure that we are active */
2876 e_tx_state = NOTIFY_STATE_ACTIVE;
2878 /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
2879 if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2880 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2882 /* set time for power dialing */
2883 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
2886 /* set redial tone */
2887 if (ea_endpoint->ep_portlist) {
2890 set_tone(ea_endpoint->ep_portlist, "redial");
2891 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);
2892 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2893 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2894 new_state(EPOINT_STATE_IN_PROCEEDING);
2895 if (ea_endpoint->ep_portlist) {
2896 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2897 message_put(message);
2898 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2900 /* caused the error, that the first knock sound was not there */
2901 /* set_tone(portlist, "proceeding"); */
2903 /* send display of powerdialing */
2904 if (e_ext.display_dialing) {
2905 portlist = ea_endpoint->ep_portlist;
2907 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2909 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2911 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2912 message_put(message);
2913 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2914 portlist = portlist->next;
2923 if ((e_state!=EPOINT_STATE_CONNECT
2924 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2925 && e_state!=EPOINT_STATE_IN_OVERLAP
2926 && e_state!=EPOINT_STATE_IN_PROCEEDING
2927 && e_state!=EPOINT_STATE_IN_ALERTING)
2928 || !ea_endpoint->ep_portlist) { /* or no port */
2929 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2930 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */
2931 return; /* must exit here */
2934 if (!e_join_cause) {
2935 e_join_cause = param->disconnectinfo.cause;
2936 e_join_location = param->disconnectinfo.location;
2939 /* on release we need the audio again! */
2940 if (message_type == MESSAGE_RELEASE) {
2942 ea_endpoint->ep_join_id = 0;
2944 /* disconnect and select tone */
2945 new_state(EPOINT_STATE_OUT_DISCONNECT);
2946 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2947 /* if own_cause, we must release the join */
2948 if (e_ext.own_cause /* own cause */
2949 || !e_join_pattern) { /* no patterns */
2950 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);
2951 if (message_type != MESSAGE_RELEASE)
2952 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2954 } else { /* else we enable audio */
2955 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2956 message->param.audiopath = 1;
2957 message_put(message);
2959 /* send disconnect message */
2960 SCPY(e_tone, cause);
2961 portlist = ea_endpoint->ep_portlist;
2963 set_tone(portlist, cause);
2964 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2965 portlist = portlist->next;
2969 /* join MESSAGE_SETUP */
2970 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2972 struct lcr_msg *message;
2973 // struct interface *interface;
2975 /* if we already in setup state, we just update the dialing with new digits */
2976 if (e_state == EPOINT_STATE_OUT_SETUP
2977 || e_state == EPOINT_STATE_OUT_OVERLAP) {
2978 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
2979 /* if digits changed, what we have already dialed */
2980 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
2981 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);
2982 /* release all ports */
2983 while((portlist = ea_endpoint->ep_portlist)) {
2984 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2985 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2986 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2987 message_put(message);
2988 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2989 ea_endpoint->free_portlist(portlist);
2992 /* disconnect audio */
2993 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2994 message->param.audiopath = 0;
2995 message_put(message);
2997 /* get dialing info */
2998 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
2999 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3000 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3001 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3002 new_state(EPOINT_STATE_OUT_OVERLAP);
3005 e_redial = now_d + 1; /* set redial one second in the future */
3008 /* if we have a pending redial, so we just adjust the dialing number */
3010 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);
3011 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3014 if (!ea_endpoint->ep_portlist) {
3015 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3017 if (ea_endpoint->ep_portlist->next) {
3018 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3020 if (e_state == EPOINT_STATE_OUT_SETUP) {
3022 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);
3023 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3026 /* get what we have not dialed yet */
3027 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));
3028 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3029 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3030 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3031 message_put(message);
3032 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3034 /* always store what we have dialed or queued */
3035 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3039 if (e_state != EPOINT_STATE_IDLE) {
3040 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3043 /* if an internal extension is dialed, copy that number */
3044 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3045 SCPY(e_ext.number, param->setup.dialinginfo.id);
3046 /* if an internal extension is dialed, get extension's info about caller */
3047 if (e_ext.number[0]) {
3048 if (!read_extension(&e_ext, e_ext.number)) {
3049 e_ext.number[0] = '\0';
3050 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3054 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3055 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3056 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3057 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3059 /* process (voice over) data calls */
3060 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3061 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3062 memset(&e_capainfo, 0, sizeof(e_capainfo));
3063 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3064 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3065 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3068 new_state(EPOINT_STATE_OUT_SETUP);
3069 /* call special setup routine */
3073 /* join MESSAGE_mISDNSIGNAL */
3074 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3076 struct lcr_msg *message;
3079 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3080 memcpy(&message->param, param, sizeof(union parameter));
3081 message_put(message);
3082 portlist = portlist->next;
3086 /* join MESSAGE_NOTIFY */
3087 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3089 struct lcr_msg *message;
3092 if (param->notifyinfo.notify) {
3093 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3094 // /* if notification was generated locally, we turn hold music on/off */
3095 // if (param->notifyinfo.local)
3096 // 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)
3100 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3101 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3103 set_tone(portlist, "");
3104 portlist = portlist->next;
3107 portlist = ea_endpoint->ep_portlist;
3112 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3114 set_tone(portlist, "hold");
3115 portlist = portlist->next;
3117 portlist = ea_endpoint->ep_portlist;
3122 /* save new state */
3123 e_tx_state = new_state;
3126 /* notify port(s) about it */
3128 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3129 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3130 /* handle restricted caller ids */
3131 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3132 /* display callerid if desired for extension */
3133 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));
3134 message_put(message);
3135 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3136 portlist = portlist->next;
3140 /* JOIN sends messages to the endpoint
3142 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3144 struct port_list *portlist;
3145 struct lcr_msg *message;
3148 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3152 portlist = ea_endpoint->ep_portlist;
3154 /* send MESSAGE_DATA to port */
3155 if (message_type == MESSAGE_DATA) {
3156 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3157 /* skip if no port relation */
3160 /* skip if more than one port relation */
3163 /* forward audio data to port */
3164 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3169 // 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);
3170 switch(message_type) {
3171 /* JOIN SENDS TONE message */
3173 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);
3174 set_tone(portlist, param->tone.name);
3177 /* JOIN SENDS CRYPT message */
3179 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);
3180 join_crypt(portlist, message_type, param);
3183 /* JOIN sends INFORMATION message */
3184 case MESSAGE_INFORMATION:
3185 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);
3186 join_information(portlist, message_type, param);
3189 /* JOIN sends FACILITY message */
3190 case MESSAGE_FACILITY:
3191 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);
3192 join_facility(portlist, message_type, param);
3195 /* JOIN sends OVERLAP message */
3196 case MESSAGE_OVERLAP:
3197 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);
3198 if (e_state!=EPOINT_STATE_IN_SETUP
3199 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3200 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3203 join_overlap(portlist, message_type, param);
3206 /* JOIN sends PROCEEDING message */
3207 case MESSAGE_PROCEEDING:
3208 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);
3209 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3210 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3213 join_proceeding(portlist, message_type, param);
3216 /* JOIN sends ALERTING message */
3217 case MESSAGE_ALERTING:
3218 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);
3219 if (e_state!=EPOINT_STATE_IN_OVERLAP
3220 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3221 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3224 join_alerting(portlist, message_type, param);
3227 /* JOIN sends CONNECT message */
3228 case MESSAGE_CONNECT:
3229 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);
3230 if (e_state!=EPOINT_STATE_IN_OVERLAP
3231 && e_state!=EPOINT_STATE_IN_PROCEEDING
3232 && e_state!=EPOINT_STATE_IN_ALERTING) {
3233 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3236 join_connect(portlist, message_type, param);
3239 /* JOIN sends DISCONNECT/RELEASE message */
3240 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3241 case MESSAGE_RELEASE: /* JOIN releases */
3242 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);
3243 join_disconnect_release(message_type, param);
3246 /* JOIN sends SETUP message */
3248 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);
3249 join_setup(portlist, message_type, param);
3252 /* JOIN sends special mISDNSIGNAL message */
3253 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3254 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);
3255 join_mISDNsignal(portlist, message_type, param);
3259 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3260 /* JOIN requests bchannel */
3261 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3262 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);
3263 /* only one port is expected to be connected to bchannel */
3270 set_tone(portlist, NULL);
3271 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3272 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3276 /* JOIN has pattern available */
3277 case MESSAGE_PATTERN: /* indicating pattern available */
3278 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);
3279 if (!e_join_pattern) {
3280 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3284 set_tone(portlist, NULL);
3285 portlist = portlist->next;
3287 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3288 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3289 message->param.audiopath = 1;
3290 message_put(message);
3294 /* JOIN has no pattern available */
3295 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3296 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);
3297 if (e_join_pattern) {
3298 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3300 /* disconnect our audio tx and rx */
3301 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3302 message->param.audiopath = 0;
3303 message_put(message);
3308 /* JOIN (dunno at the moment) */
3309 case MESSAGE_REMOTE_AUDIO:
3310 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);
3311 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3312 message->param.audiopath = param->channel;
3313 message_put(message);
3317 /* JOIN sends a notify message */
3318 case MESSAGE_NOTIFY:
3319 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);
3320 join_notify(portlist, message_type, param);
3323 /* JOIN wants keypad / dtmf */
3324 case MESSAGE_ENABLEKEYPAD:
3325 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);
3328 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3333 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);
3338 /* pick_join will connect the first incoming call found. the endpoint
3339 * will receivce a MESSAGE_CONNECT.
3341 int match_list(char *list, char *item)
3343 char *end, *next = NULL;
3345 /* no list make matching */
3350 /* eliminate white spaces */
3351 while (*list <= ' ')
3357 /* if end of list is reached, we return */
3358 if (list[0] == '\0')
3360 /* if we have more than one entry (left) */
3361 if ((end = strchr(list, ',')))
3364 next = end = strchr(list, '\0');
3365 while (*(end-1) <= ' ')
3367 /* if string part matches item */
3368 if (!strncmp(list, item, end-list))
3374 void EndpointAppPBX::pick_join(char *extensions)
3376 struct lcr_msg *message;
3377 struct port_list *portlist;
3379 class EndpointAppPBX *eapp, *found;
3381 class JoinPBX *joinpbx;
3382 struct join_relation *relation;
3385 /* find an endpoint that is ringing internally or vbox with higher priority */
3388 eapp = apppbx_first;
3390 if (eapp!=this && ea_endpoint->ep_portlist) {
3391 portlist = eapp->ea_endpoint->ep_portlist;
3393 if ((port = find_port_id(portlist->port_id))) {
3394 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3395 if (match_list(extensions, eapp->e_ext.number)) {
3401 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3402 && port->p_state==PORT_STATE_OUT_ALERTING)
3403 if (match_list(extensions, eapp->e_ext.number)) {
3407 portlist = portlist->next;
3415 /* if no endpoint found */
3417 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);
3419 set_tone(ea_endpoint->ep_portlist, "cause_10");
3420 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3421 new_state(EPOINT_STATE_OUT_DISCONNECT);
3426 if (ea_endpoint->ep_join_id) {
3427 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3430 if (!eapp->ea_endpoint->ep_join_id) {
3431 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3434 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3436 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3439 if (join->j_type != JOIN_TYPE_PBX) {
3440 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3443 joinpbx = (class JoinPBX *)join;
3444 relation = joinpbx->j_relation;
3446 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3449 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3450 relation = relation->next;
3452 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3457 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3459 if (options.deb & DEBUG_EPOINT) {
3460 class Join *debug_c = join_first;
3461 class Endpoint *debug_e = epoint_first;
3462 class Port *debug_p = port_first;
3464 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3466 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3468 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3469 debug_c = debug_c->next;
3471 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3473 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3474 debug_e = debug_e->next;
3476 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3478 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3479 debug_p = debug_p->next;
3484 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3485 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3486 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3488 /* connnecting our endpoint */
3489 new_state(EPOINT_STATE_CONNECT);
3490 if (e_ext.number[0])
3492 set_tone(ea_endpoint->ep_portlist, NULL);
3494 /* now we send a release to the ringing endpoint */
3495 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3496 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3497 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3498 message_put(message);
3500 /* we send a connect to the join with our caller id */
3501 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3502 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3503 message->param.connectinfo.present = e_callerinfo.present;
3504 message->param.connectinfo.screen = e_callerinfo.screen;
3505 message->param.connectinfo.itype = e_callerinfo.itype;
3506 message->param.connectinfo.ntype = e_callerinfo.ntype;
3507 message_put(message);
3509 /* we send a connect to our port with the remote callerid */
3510 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3511 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3512 message->param.connectinfo.present = eapp->e_callerinfo.present;
3513 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3514 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3515 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3516 /* handle restricted caller ids */
3517 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);
3518 /* display callerid if desired for extension */
3519 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));
3520 message_put(message);
3522 /* we send a connect to the audio path (not for vbox) */
3523 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3524 message->param.audiopath = 1;
3525 message_put(message);
3527 /* beeing paranoid, we make call update */
3528 joinpbx->j_updatebridge = 1;
3530 if (options.deb & DEBUG_EPOINT) {
3531 class Join *debug_c = join_first;
3532 class Endpoint *debug_e = epoint_first;
3533 class Port *debug_p = port_first;
3535 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3537 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3539 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3540 debug_c = debug_c->next;
3542 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3544 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3545 debug_e = debug_e->next;
3547 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3549 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3550 debug_p = debug_p->next;
3556 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3558 void EndpointAppPBX::join_join(void)
3560 struct lcr_msg *message;
3561 struct join_relation *our_relation, *other_relation;
3562 struct join_relation **our_relation_pointer, **other_relation_pointer;
3563 class Join *our_join, *other_join;
3564 class JoinPBX *our_joinpbx, *other_joinpbx;
3565 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3566 class Port *our_port, *other_port;
3567 class Pdss1 *our_pdss1, *other_pdss1;
3569 /* are we a candidate to join a join? */
3570 our_join = find_join_id(ea_endpoint->ep_join_id);
3572 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3575 if (our_join->j_type != JOIN_TYPE_PBX) {
3576 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3579 our_joinpbx = (class JoinPBX *)our_join;
3580 if (!ea_endpoint->ep_portlist) {
3581 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3584 if (!e_ext.number[0]) {
3585 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3588 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3590 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3593 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3594 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3597 our_pdss1 = (class Pdss1 *)our_port;
3599 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3600 other_eapp = apppbx_first;
3602 if (other_eapp == this) {
3603 other_eapp = other_eapp->next;
3606 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);
3607 if (other_eapp->e_ext.number[0] /* has terminal */
3608 && other_eapp->ea_endpoint->ep_portlist /* has port */
3609 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3610 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3611 if (other_port) { /* port still exists */
3612 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3613 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3614 other_pdss1 = (class Pdss1 *)other_port;
3615 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);
3616 if (other_pdss1->p_m_hold /* port is on hold */
3617 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3618 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3621 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3624 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3627 other_eapp = other_eapp->next;
3630 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3633 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3635 /* if we have the same join */
3636 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3637 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3640 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3642 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3645 if (other_join->j_type != JOIN_TYPE_PBX) {
3646 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3649 other_joinpbx = (class JoinPBX *)other_join;
3650 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3651 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3655 /* remove relation to endpoint for join on hold */
3656 other_relation = other_joinpbx->j_relation;
3657 other_relation_pointer = &other_joinpbx->j_relation;
3658 while(other_relation) {
3659 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3660 /* detach other endpoint on hold */
3661 *other_relation_pointer = other_relation->next;
3662 FREE(other_relation, sizeof(struct join_relation));
3664 other_relation = *other_relation_pointer;
3665 other_eapp->ea_endpoint->ep_join_id = 0;
3669 /* change join/hold pointer of endpoint to the new join */
3670 temp_epoint = find_epoint_id(other_relation->epoint_id);
3672 if (temp_epoint->ep_join_id == other_join->j_serial)
3673 temp_epoint->ep_join_id = our_join->j_serial;
3676 other_relation_pointer = &other_relation->next;
3677 other_relation = other_relation->next;
3679 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3681 /* join call relations */
3682 our_relation = our_joinpbx->j_relation;
3683 our_relation_pointer = &our_joinpbx->j_relation;
3684 while(our_relation) {
3685 our_relation_pointer = &our_relation->next;
3686 our_relation = our_relation->next;
3688 *our_relation_pointer = other_joinpbx->j_relation;
3689 other_joinpbx->j_relation = NULL;
3690 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3692 /* release endpoint on hold */
3693 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3694 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3695 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3696 message_put(message);
3698 /* if we are not a partyline, we get partyline state from other join */
3699 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3701 /* remove empty join */
3703 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3705 /* mixer must update */
3706 our_joinpbx->j_updatebridge = 1; /* update mixer flag */
3708 /* we send a retrieve to that endpoint */
3709 // mixer will update the hold-state of the join and send it to the endpoints is changes
3713 /* check if we have an external call
3714 * this is used to check for encryption ability
3716 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3718 struct join_relation *relation;
3720 class JoinPBX *joinpbx;
3721 class Endpoint *epoint;
3723 /* some paranoia check */
3724 if (!ea_endpoint->ep_portlist) {
3725 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3726 *errstr = "No Call";
3729 if (!e_ext.number[0]) {
3730 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3731 *errstr = "No Call";
3735 /* check if we have a join with 2 parties */
3736 join = find_join_id(ea_endpoint->ep_join_id);
3738 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3739 *errstr = "No Call";
3742 if (join->j_type != JOIN_TYPE_PBX) {
3743 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3744 *errstr = "No PBX Call";
3747 joinpbx = (class JoinPBX *)join;
3748 relation = joinpbx->j_relation;
3750 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3751 *errstr = "No Call";
3754 if (!relation->next) {
3755 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3756 *errstr = "No Call";
3759 if (relation->next->next) {
3760 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3761 *errstr = "Err: Conference";
3764 if (relation->epoint_id == ea_endpoint->ep_serial) {
3765 relation = relation->next;
3766 if (relation->epoint_id == ea_endpoint->ep_serial) {
3767 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3768 *errstr = "Software Error";
3773 /* check remote port for external call */
3774 epoint = find_epoint_id(relation->epoint_id);
3776 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3777 *errstr = "No Call";
3780 if (!epoint->ep_portlist) {
3781 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3782 *errstr = "No Call";
3785 *port = find_port_id(epoint->ep_portlist->port_id);
3787 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3788 *errstr = "No Call";
3791 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3792 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3793 *errstr = "No Ext Call";
3796 if ((*port)->p_state != PORT_STATE_CONNECT) {
3797 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3798 *errstr = "No Ext Connect";
3804 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3806 const char *logtext = "unknown";
3809 switch(message_type) {
3811 trace_header("SETUP", dir);
3812 if (dir == DIRECTION_OUT)
3813 add_trace("to", NULL, "CH(%lu)", port_id);
3814 if (dir == DIRECTION_IN)
3815 add_trace("from", NULL, "CH(%lu)", port_id);
3816 if (param->setup.callerinfo.extension[0])
3817 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3818 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3819 switch(param->setup.callerinfo.present) {
3820 case INFO_PRESENT_RESTRICTED:
3821 add_trace("caller id", "present", "restricted");
3823 case INFO_PRESENT_ALLOWED:
3824 add_trace("caller id", "present", "allowed");
3827 add_trace("caller id", "present", "not available");
3829 if (param->setup.callerinfo.ntype2) {
3830 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3831 switch(param->setup.callerinfo.present) {
3832 case INFO_PRESENT_RESTRICTED:
3833 add_trace("caller id2", "present", "restricted");
3835 case INFO_PRESENT_ALLOWED:
3836 add_trace("caller id2", "present", "allowed");
3839 add_trace("caller id2", "present", "not available");
3842 if (param->setup.redirinfo.id[0]) {
3843 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3844 switch(param->setup.redirinfo.present) {
3845 case INFO_PRESENT_RESTRICTED:
3846 add_trace("redir'ing", "present", "restricted");
3848 case INFO_PRESENT_ALLOWED:
3849 add_trace("redir'ing", "present", "allowed");
3852 add_trace("redir'ing", "present", "not available");
3855 if (param->setup.dialinginfo.id[0])
3856 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3857 if (param->setup.dialinginfo.keypad[0])
3858 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3859 if (param->setup.dialinginfo.display[0])
3860 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3861 if (param->setup.dialinginfo.sending_complete)
3862 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3866 case MESSAGE_OVERLAP:
3867 trace_header("SETUP ACKNOWLEDGE", dir);
3868 if (dir == DIRECTION_OUT)
3869 add_trace("to", NULL, "CH(%lu)", port_id);
3870 if (dir == DIRECTION_IN)
3871 add_trace("from", NULL, "CH(%lu)", port_id);
3875 case MESSAGE_PROCEEDING:
3876 trace_header("PROCEEDING", dir);
3877 if (dir == DIRECTION_OUT)
3878 add_trace("to", NULL, "CH(%lu)", port_id);
3879 if (dir == DIRECTION_IN)
3880 add_trace("from", NULL, "CH(%lu)", port_id);
3884 case MESSAGE_ALERTING:
3885 trace_header("ALERTING", dir);
3886 if (dir == DIRECTION_OUT)
3887 add_trace("to", NULL, "CH(%lu)", port_id);
3888 if (dir == DIRECTION_IN)
3889 add_trace("from", NULL, "CH(%lu)", port_id);
3893 case MESSAGE_CONNECT:
3894 trace_header("CONNECT", dir);
3895 if (dir == DIRECTION_OUT)
3896 add_trace("to", NULL, "CH(%lu)", port_id);
3897 if (dir == DIRECTION_IN)
3898 add_trace("from", NULL, "CH(%lu)", port_id);
3899 if (param->connectinfo.extension[0])
3900 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3901 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3902 switch(param->connectinfo.present) {
3903 case INFO_PRESENT_RESTRICTED:
3904 add_trace("connect id", "present", "restricted");
3906 case INFO_PRESENT_ALLOWED:
3907 add_trace("connect id", "present", "allowed");
3910 add_trace("connect id", "present", "not available");
3912 if (param->connectinfo.display[0])
3913 add_trace("display", NULL, "%s", param->connectinfo.display);
3917 case MESSAGE_DISCONNECT:
3918 case MESSAGE_RELEASE:
3919 if (message_type == MESSAGE_DISCONNECT)
3920 trace_header("DISCONNECT", dir);
3922 trace_header("RELEASE", dir);
3923 if (dir == DIRECTION_OUT)
3924 add_trace("to", NULL, "CH(%lu)", port_id);
3925 if (dir == DIRECTION_IN)
3926 add_trace("from", NULL, "CH(%lu)", port_id);
3927 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3928 switch(param->disconnectinfo.location) {
3930 add_trace("cause", "location", "0-User");
3932 case LOCATION_PRIVATE_LOCAL:
3933 add_trace("cause", "location", "1-Local-PBX");
3935 case LOCATION_PUBLIC_LOCAL:
3936 add_trace("cause", "location", "2-Local-Exchange");
3938 case LOCATION_TRANSIT:
3939 add_trace("cause", "location", "3-Transit");
3941 case LOCATION_PUBLIC_REMOTE:
3942 add_trace("cause", "location", "4-Remote-Exchange");
3944 case LOCATION_PRIVATE_REMOTE:
3945 add_trace("cause", "location", "5-Remote-PBX");
3947 case LOCATION_INTERNATIONAL:
3948 add_trace("cause", "location", "7-International-Exchange");
3950 case LOCATION_BEYOND:
3951 add_trace("cause", "location", "10-Beyond-Interworking");
3954 add_trace("cause", "location", "%d", param->disconnectinfo.location);
3956 if (param->disconnectinfo.display[0])
3957 add_trace("display", NULL, "%s", param->disconnectinfo.display);
3961 case MESSAGE_NOTIFY:
3962 switch(param->notifyinfo.notify) {
3967 logtext = "USER_SUSPENDED";
3970 logtext = "BEARER_SERVICE_CHANGED";
3973 logtext = "USER_RESUMED";
3976 logtext = "CONFERENCE_ESTABLISHED";
3979 logtext = "CONFERENCE_DISCONNECTED";
3982 logtext = "OTHER_PARTY_ADDED";
3985 logtext = "ISOLATED";
3988 logtext = "REATTACHED";
3991 logtext = "OTHER_PARTY_ISOLATED";
3994 logtext = "OTHER_PARTY_REATTACHED";
3997 logtext = "OTHER_PARTY_SPLIT";
4000 logtext = "OTHER_PARTY_DISCONNECTED";
4003 logtext = "CONFERENCE_FLOATING";
4006 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4009 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4012 logtext = "CALL_IS_A_WAITING_CALL";
4015 logtext = "DIVERSION_ACTIVATED";
4018 logtext = "RESERVED_CT_1";
4021 logtext = "RESERVED_CT_2";
4024 logtext = "REVERSE_CHARGING";
4027 logtext = "REMOTE_HOLD";
4030 logtext = "REMOTE_RETRIEVAL";
4033 logtext = "CALL_IS_DIVERTING";
4036 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4040 trace_header("NOTIFY", dir);
4041 if (dir == DIRECTION_OUT)
4042 add_trace("to", NULL, "CH(%lu)", port_id);
4043 if (dir == DIRECTION_IN)
4044 add_trace("from", NULL, "CH(%lu)", port_id);
4045 if (param->notifyinfo.notify)
4046 add_trace("indicator", NULL, "%s", logtext);
4047 if (param->notifyinfo.id[0]) {
4048 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4049 switch(param->notifyinfo.present) {
4050 case INFO_PRESENT_RESTRICTED:
4051 add_trace("redir'on", "present", "restricted");
4053 case INFO_PRESENT_ALLOWED:
4054 add_trace("redir'on", "present", "allowed");
4057 add_trace("redir'on", "present", "not available");
4060 if (param->notifyinfo.display[0])
4061 add_trace("display", NULL, "%s", param->notifyinfo.display);
4065 case MESSAGE_INFORMATION:
4066 trace_header("INFORMATION", dir);
4067 if (dir == DIRECTION_OUT)
4068 add_trace("to", NULL, "CH(%lu)", port_id);
4069 if (dir == DIRECTION_IN)
4070 add_trace("from", NULL, "CH(%lu)", port_id);
4071 if (param->information.id[0])
4072 add_trace("dialing", NULL, "%s", param->information.id);
4073 if (param->information.display[0])
4074 add_trace("display", NULL, "%s", param->information.display);
4075 if (param->information.sending_complete)
4076 add_trace("complete", NULL, "true", param->information.sending_complete);
4080 case MESSAGE_FACILITY:
4081 trace_header("FACILITY", dir);
4082 if (dir == DIRECTION_OUT)
4083 add_trace("to", NULL, "CH(%lu)", port_id);
4084 if (dir == DIRECTION_IN)
4085 add_trace("from", NULL, "CH(%lu)", port_id);
4090 trace_header("TONE", dir);
4091 if (dir == DIRECTION_OUT)
4092 add_trace("to", NULL, "CH(%lu)", port_id);
4093 if (dir == DIRECTION_IN)
4094 add_trace("from", NULL, "CH(%lu)", port_id);
4095 if (param->tone.name[0]) {
4096 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4097 add_trace("name", NULL, "%s", param->tone.name);
4099 add_trace("off", NULL, NULL);
4103 case MESSAGE_SUSPEND:
4104 case MESSAGE_RESUME:
4105 if (message_type == MESSAGE_SUSPEND)
4106 trace_header("SUSPEND", dir);
4108 trace_header("RESUME", dir);
4109 if (dir == DIRECTION_OUT)
4110 add_trace("to", NULL, "CH(%lu)", port_id);
4111 if (dir == DIRECTION_IN)
4112 add_trace("from", NULL, "CH(%lu)", port_id);
4113 if (param->parkinfo.len)
4114 add_trace("length", NULL, "%d", param->parkinfo.len);
4119 case MESSAGE_BCHANNEL:
4120 trace_header("BCHANNEL", dir);
4121 switch(param->bchannel.type) {
4122 case BCHANNEL_REQUEST:
4123 add_trace("type", NULL, "request");
4125 case BCHANNEL_ASSIGN:
4126 add_trace("type", NULL, "assign");
4128 case BCHANNEL_ASSIGN_ACK:
4129 add_trace("type", NULL, "assign_ack");
4131 case BCHANNEL_REMOVE:
4132 add_trace("type", NULL, "remove");
4134 case BCHANNEL_REMOVE_ACK:
4135 add_trace("type", NULL, "remove_ack");
4138 if (param->bchannel.addr)
4139 add_trace("address", NULL, "%x", param->bchannel.addr);
4145 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4149 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4151 struct lcr_msg *message;
4155 if (!portlist->port_id)
4158 if (!e_connectedmode) {
4159 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4160 message->param.disconnectinfo.cause = cause;
4161 message->param.disconnectinfo.location = location;
4163 SCPY(message->param.disconnectinfo.display, display);
4165 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4167 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4169 SCPY(message->param.notifyinfo.display, display);
4171 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4173 message_put(message);
4174 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);