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));
1438 // e_dtmf = param->setup.dtmf;
1439 /* screen incoming caller id */
1440 interface = interface_first;
1442 if (!strcmp(e_callerinfo.interface, interface->name)) {
1445 interface = interface->next;
1448 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1449 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1452 /* process extension */
1453 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1454 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1455 /* port makes call from extension */
1456 SCPY(e_callerinfo.extension, e_callerinfo.id);
1457 SCPY(e_ext.number, e_callerinfo.extension);
1458 SCPY(e_extension_interface, e_callerinfo.interface);
1460 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1463 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1464 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1466 /* get extension's info about caller */
1467 if (!read_extension(&e_ext, e_ext.number)) {
1468 /* extension doesn't exist */
1469 trace_header("EXTENSION (not created)", DIRECTION_IN);
1470 add_trace("extension", NULL, "%s", e_ext.number);
1472 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1473 new_state(EPOINT_STATE_OUT_DISCONNECT);
1474 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1475 e_ext.number[0] = '\0'; /* no terminal */
1480 /* put prefix (next) in front of e_dialinginfo.id */
1481 if (e_ext.next[0]) {
1482 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1483 SCPY(e_dialinginfo.id, buffer);
1484 e_ext.next[0] = '\0';
1486 } else if (e_ext.prefix[0]) {
1487 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1488 SCPY(e_dialinginfo.id, buffer);
1491 /* screen caller id by extension's config */
1492 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1494 SCPY(e_callerinfo.name, e_ext.name);
1495 /* use caller id (or if exist: id_next_call) for this call */
1496 if (e_ext.id_next_call_present >= 0) {
1497 SCPY(e_callerinfo.id, e_ext.id_next_call);
1498 /* if we restrict the pesentation */
1499 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1500 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1501 else e_callerinfo.present = e_ext.id_next_call_present;
1502 e_callerinfo.ntype = e_ext.id_next_call_type;
1503 e_ext.id_next_call_present = -1;
1506 SCPY(e_callerinfo.id, e_ext.callerid);
1507 /* if we restrict the pesentation */
1508 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1509 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1510 else e_callerinfo.present = e_ext.callerid_present;
1511 e_callerinfo.ntype = e_ext.callerid_type;
1513 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1515 /* extension is written */
1517 write_extension(&e_ext, e_ext.number);
1519 /* set volume of rx and tx */
1520 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1521 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1522 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1523 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1524 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1525 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1526 message_put(message);
1529 /* start recording if enabled */
1530 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1531 /* check if we are a terminal */
1532 if (e_ext.number[0] == '\0')
1533 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1535 port = find_port_id(portlist->port_id);
1537 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1541 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1542 /* no terminal identification */
1543 e_ext.number[0] = '\0';
1544 e_extension_interface[0] = '\0';
1545 memset(&e_ext, 0, sizeof(e_ext));
1546 e_ext.rights = 4; /* right to dial internat */
1550 e_ruleset = ruleset_main;
1552 e_rule = e_ruleset->rule_first;
1554 e_extdialing = e_dialinginfo.id;
1555 new_state(EPOINT_STATE_IN_SETUP);
1556 if (e_dialinginfo.id[0]) {
1557 set_tone(portlist, "dialing");
1559 if (e_ext.number[0])
1560 set_tone(portlist, "dialpbx");
1562 set_tone(portlist, "dialtone");
1565 if (e_state == EPOINT_STATE_IN_SETUP) {
1566 /* request MORE info, if not already at higher state */
1567 new_state(EPOINT_STATE_IN_OVERLAP);
1568 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1569 message_put(message);
1570 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1574 /* port MESSAGE_INFORMATION */
1575 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1577 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1579 /* ignore information message without digit information */
1580 if (!param->information.id[0])
1585 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1587 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1592 /* if vbox_play is done, the information are just used as they come */
1594 if (e_action->index == ACTION_VBOX_PLAY) {
1595 /* concat dialing string */
1596 SCAT(e_dialinginfo.id, param->information.id);
1601 /* keypad when disconnect but in connected mode */
1602 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1603 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1604 /* processing keypad function */
1605 if (param->information.id[0] == '0') {
1611 /* keypad when connected */
1612 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1613 if (e_ext.keypad || e_enablekeypad) {
1614 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1615 /* processing keypad function */
1616 if (param->information.id[0] == '0') {
1619 if (param->information.id[0])
1620 keypad_function(param->information.id[0]);
1622 if (e_ext.number[0])
1623 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1625 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1630 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1631 if (e_ext.number[0])
1632 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1634 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1638 if (!param->information.id[0])
1640 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1641 set_tone(portlist, "dialing");
1644 if (e_action->index==ACTION_OUTDIAL
1645 || e_action->index==ACTION_EXTERNAL
1646 || e_action->index==ACTION_REMOTE) {
1648 set_tone(portlist, "dialing");
1649 else if (!e_extdialing[0])
1650 set_tone(portlist, "dialing");
1652 /* concat dialing string */
1653 SCAT(e_dialinginfo.id, param->information.id);
1657 /* port MESSAGE_DTMF */
1658 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1660 /* only if dtmf detection is enabled */
1662 trace_header("DTMF (disabled)", DIRECTION_IN);
1666 trace_header("DTMF", DIRECTION_IN);
1667 add_trace("digit", NULL, "%c", param->dtmf);
1671 NOTE: vbox is now handled due to overlap state
1672 /* if vbox_play is done, the dtmf digits are just used as they come */
1674 if (e_action->index == ACTION_VBOX_PLAY) {
1675 /* concat dialing string */
1676 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1677 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1678 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1681 /* continue to process *X# sequences */
1685 /* check for *X# sequence */
1686 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1687 if (e_dtmf_time+3 < now) {
1688 /* the last digit was too far in the past to be a sequence */
1689 if (param->dtmf == '*')
1690 /* only start is allowed in the sequence */
1695 /* we have a sequence of digits, see what we got */
1696 if (param->dtmf == '*')
1698 else if (param->dtmf>='0' && param->dtmf<='9') {
1699 /* we need to have a star before we receive the digit of the sequence */
1700 if (e_dtmf_last == '*')
1701 e_dtmf_last = param->dtmf;
1702 } else if (param->dtmf == '#') {
1704 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1705 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1706 if (e_dtmf_last == '0') {
1710 /* processing keypad function */
1712 keypad_function(e_dtmf_last);
1718 /* set last time of dtmf */
1723 /* check for ## hookflash during dialing */
1725 if (e_action->index==ACTION_PASSWORD
1726 || e_action->index==ACTION_PASSWORD_WRITE)
1728 if (param->dtmf=='#') { /* current digit is '#' */
1729 if (e_state==EPOINT_STATE_IN_DISCONNECT
1730 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1744 /* dialing using dtmf digit */
1745 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1746 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1747 set_tone(portlist, "dialing");
1749 /* concat dialing string */
1750 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1751 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1752 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1758 /* port MESSAGE_CRYPT */
1759 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1761 /* send crypt response to cryptman */
1762 if (param->crypt.type == CR_MESSAGE_IND)
1763 cryptman_msg2man(param->crypt.data, param->crypt.len);
1765 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1768 /* port MESSAGE_OVERLAP */
1769 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1771 struct lcr_msg *message;
1773 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1775 /* signal to call tool */
1776 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1778 if (e_dialing_queue[0] && portlist) {
1779 /* send what we have not dialed yet, because we had no setup complete */
1780 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1781 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1782 SCPY(message->param.information.id, e_dialing_queue);
1783 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1784 message_put(message);
1785 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1786 e_dialing_queue[0] = '\0';
1788 /* check if pattern is available */
1789 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1790 /* indicate patterns */
1791 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1792 message_put(message);
1794 /* connect audio, if not already */
1795 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1796 message->param.audiopath = 1;
1797 message_put(message);
1799 /* indicate no patterns */
1800 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1801 message_put(message);
1803 /* disconnect audio, if not already */
1804 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1805 message->param.audiopath = 0;
1806 message_put(message);
1808 new_state(EPOINT_STATE_OUT_OVERLAP);
1809 /* if we are in a join */
1810 if (ea_endpoint->ep_join_id) {
1811 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1812 memcpy(&message->param, param, sizeof(union parameter));
1813 message_put(message);
1817 /* port MESSAGE_PROCEEDING */
1818 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1820 struct lcr_msg *message;
1822 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1824 /* signal to call tool */
1825 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1827 e_state = EPOINT_STATE_OUT_PROCEEDING;
1828 /* check if pattern is availatle */
1829 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1830 /* indicate patterns */
1831 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1832 message_put(message);
1834 /* connect audio, if not already */
1835 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1836 message->param.audiopath = 1;
1837 message_put(message);
1839 /* indicate no patterns */
1840 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1841 message_put(message);
1843 /* disconnect audio, if not already */
1844 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1845 message->param.audiopath = 0;
1846 message_put(message);
1848 /* if we are in a call */
1849 if (ea_endpoint->ep_join_id) {
1850 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1851 memcpy(&message->param, param, sizeof(union parameter));
1852 message_put(message);
1856 /* port MESSAGE_ALERTING */
1857 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1859 struct lcr_msg *message;
1861 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1863 /* signal to call tool */
1864 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1867 // set_tone(portlist, "hold");
1869 new_state(EPOINT_STATE_OUT_ALERTING);
1870 /* check if pattern is available */
1871 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1872 /* indicate patterns */
1873 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1874 message_put(message);
1876 /* connect audio, if not already */
1877 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1878 message->param.audiopath = 1;
1879 message_put(message);
1881 /* indicate no patterns */
1882 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1883 message_put(message);
1885 /* disconnect audio, if not already */
1886 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1887 message->param.audiopath = 0;
1888 message_put(message);
1890 /* if we are in a call */
1891 if (ea_endpoint->ep_join_id) {
1892 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1893 memcpy(&message->param, param, sizeof(union parameter));
1894 message_put(message);
1898 /* port MESSAGE_CONNECT */
1899 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1901 struct lcr_msg *message;
1903 unsigned int port_id = portlist->port_id;
1904 struct port_list *tportlist;
1906 struct interface *interface;
1908 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1910 /* signal to call tool */
1911 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1913 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1914 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1915 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1916 tportlist = ea_endpoint->ep_portlist;
1917 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1918 tportlist = tportlist->next;
1919 if (tportlist->port_id == port_id)
1920 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1921 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1922 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1923 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1924 message_put(message);
1925 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1926 ea_endpoint->free_portlist(tportlist);
1928 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1932 /* screen incoming connected id */
1933 interface = interface_first;
1935 if (!strcmp(e_connectinfo.interface, interface->name)) {
1938 interface = interface->next;
1941 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1943 /* screen connected name */
1945 SCPY(e_connectinfo.name, e_ext.name);
1947 /* add internal id to colp */
1948 SCPY(e_connectinfo.extension, e_ext.number);
1950 /* we store the connected port number */
1951 SCPY(e_extension_interface, e_connectinfo.interface);
1953 /* for internal and am calls, we get the extension's id */
1954 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1955 SCPY(e_connectinfo.id, e_ext.callerid);
1956 SCPY(e_connectinfo.extension, e_ext.number);
1957 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1958 e_connectinfo.ntype = e_ext.callerid_type;
1959 e_connectinfo.present = e_ext.callerid_present;
1961 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
1962 e_connectinfo.itype = INFO_ITYPE_VBOX;
1963 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1966 new_state(EPOINT_STATE_CONNECT);
1968 /* set volume of rx and tx */
1969 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1970 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1971 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1972 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1973 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1974 message_put(message);
1977 e_cfnr_call = e_cfnr_release = 0;
1978 if (e_ext.number[0])
1979 e_dtmf = 1; /* allow dtmf */
1982 /* other calls with no caller id (or not available for the extension) and force colp */
1983 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
1984 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
1985 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 */
1986 port = find_port_id(portlist->port_id);
1988 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
1989 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1994 /* send connect to join */
1995 if (ea_endpoint->ep_join_id) {
1996 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1997 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1998 message_put(message);
2000 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2001 message->param.audiopath = 1;
2002 message_put(message);
2003 } else if (!e_adminid) {
2005 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2006 SCPY(e_ext.number, e_cbcaller);
2007 new_state(EPOINT_STATE_IN_OVERLAP);
2008 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2010 /* get extension's info about terminal */
2011 if (!read_extension(&e_ext, e_ext.number)) {
2012 /* extension doesn't exist */
2013 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2014 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2015 new_state(EPOINT_STATE_OUT_DISCONNECT);
2016 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2020 /* put prefix in front of e_cbdialing */
2021 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2022 SCPY(e_dialinginfo.id, buffer);
2023 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2024 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2026 /* use caller id (or if exist: id_next_call) for this call */
2027 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2028 SCPY(e_callerinfo.extension, e_ext.number);
2029 if (e_ext.id_next_call_present >= 0) {
2030 SCPY(e_callerinfo.id, e_ext.id_next_call);
2031 e_callerinfo.present = e_ext.id_next_call_present;
2032 e_callerinfo.ntype = e_ext.id_next_call_type;
2033 e_ext.id_next_call_present = -1;
2034 /* extension is written */
2035 write_extension(&e_ext, e_ext.number);
2037 SCPY(e_callerinfo.id, e_ext.callerid);
2038 e_callerinfo.present = e_ext.callerid_present;
2039 e_callerinfo.ntype = e_ext.callerid_type;
2041 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2043 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2046 /* check if caller id is NOT authenticated */
2047 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2048 /* make call state to enter password */
2049 new_state(EPOINT_STATE_IN_OVERLAP);
2050 e_action = &action_password_write;
2051 e_match_timeout = 0;
2052 e_match_to_action = NULL;
2053 e_dialinginfo.id[0] = '\0';
2054 e_extdialing = strchr(e_dialinginfo.id, '\0');
2055 e_password_timeout = now+20;
2058 /* incoming call (callback) */
2059 e_ruleset = ruleset_main;
2061 e_rule = e_ruleset->rule_first;
2063 e_extdialing = e_dialinginfo.id;
2064 if (e_dialinginfo.id[0]) {
2065 set_tone(portlist, "dialing");
2068 set_tone(portlist, "dialpbx");
2071 } else { /* testcall */
2072 set_tone(portlist, "hold");
2075 /* start recording if enabled, not when answering machine answers */
2076 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)) {
2077 /* check if we are a terminal */
2078 if (e_ext.number[0] == '\0')
2079 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2081 port = find_port_id(portlist->port_id);
2083 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2088 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2089 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2091 struct lcr_msg *message;
2093 unsigned int port_id = portlist->port_id;
2097 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2099 /* signal to call tool */
2100 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2102 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2103 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2104 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2109 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);
2110 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2111 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2113 /* check if we have more than one portlist relation and we just ignore the disconnect */
2114 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2115 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2116 portlist = ea_endpoint->ep_portlist;
2118 if (portlist->port_id == port_id)
2120 portlist = portlist->next;
2123 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2124 if (message_type != MESSAGE_RELEASE) {
2125 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2126 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2127 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2128 message_put(message);
2129 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2131 ea_endpoint->free_portlist(portlist);
2132 return; /* one relation removed */
2134 if (e_state == EPOINT_STATE_CONNECT) {
2135 /* use cause from port after connect */
2136 cause = param->disconnectinfo.cause;
2137 location = param->disconnectinfo.location;
2139 /* use multipoint cause if no connect yet */
2140 if (e_multipoint_cause) {
2141 cause = e_multipoint_cause;
2142 location = e_multipoint_location;
2144 cause = CAUSE_NOUSER;
2145 location = LOCATION_PRIVATE_LOCAL;
2149 e_cfnr_call = e_cfnr_release = 0;
2151 /* process hangup */
2152 process_hangup(e_join_cause, e_join_location);
2153 e_multipoint_cause = 0;
2154 e_multipoint_location = 0;
2156 if (message_type == MESSAGE_DISCONNECT) {
2157 /* tone to disconnected end */
2158 SPRINT(buffer, "cause_%02x", cause);
2159 if (ea_endpoint->ep_portlist)
2160 set_tone(ea_endpoint->ep_portlist, buffer);
2162 new_state(EPOINT_STATE_IN_DISCONNECT);
2165 if (ea_endpoint->ep_join_id) {
2166 int haspatterns = 0;
2167 /* check if pattern is available */
2168 if (ea_endpoint->ep_portlist)
2169 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2170 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
2171 && message_type != MESSAGE_RELEASE) // if we release, we are done
2174 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2175 /* indicate patterns */
2176 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2177 message_put(message);
2178 /* connect audio, if not already */
2179 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2180 message->param.audiopath = 1;
2181 message_put(message);
2182 /* send disconnect */
2183 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2184 memcpy(&message->param, param, sizeof(union parameter));
2185 message_put(message);
2186 /* disable encryption if disconnected */
2187 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2189 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2195 if (message_type == MESSAGE_RELEASE)
2196 ea_endpoint->free_portlist(portlist);
2197 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */
2198 return; /* must exit here */
2201 /* port MESSAGE_TIMEOUT */
2202 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2206 trace_header("TIMEOUT", DIRECTION_IN);
2207 message_type = MESSAGE_DISCONNECT;
2208 switch (param->state) {
2209 case PORT_STATE_OUT_SETUP:
2210 case PORT_STATE_OUT_OVERLAP:
2211 add_trace("state", NULL, "outgoing setup/dialing");
2213 /* no user responding */
2214 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2215 return; /* must exit here */
2217 case PORT_STATE_IN_SETUP:
2218 case PORT_STATE_IN_OVERLAP:
2219 add_trace("state", NULL, "incoming setup/dialing");
2220 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2221 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2224 case PORT_STATE_OUT_PROCEEDING:
2225 add_trace("state", NULL, "outgoing proceeding");
2227 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2228 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2229 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2230 return; /* must exit here */
2232 case PORT_STATE_IN_PROCEEDING:
2233 add_trace("state", NULL, "incoming proceeding");
2234 param->disconnectinfo.cause = CAUSE_NOUSER;
2235 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2238 case PORT_STATE_OUT_ALERTING:
2239 add_trace("state", NULL, "outgoing alerting");
2241 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2242 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2243 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2244 return; /* must exit here */
2246 case PORT_STATE_CONNECT:
2247 add_trace("state", NULL, "connect");
2249 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2250 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2251 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2252 return; /* must exit here */
2254 case PORT_STATE_IN_ALERTING:
2255 add_trace("state", NULL, "incoming alerting");
2256 param->disconnectinfo.cause = CAUSE_NOANSWER;
2257 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2260 case PORT_STATE_IN_DISCONNECT:
2261 case PORT_STATE_OUT_DISCONNECT:
2262 add_trace("state", NULL, "disconnect");
2264 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2265 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2266 return; /* must exit here */
2269 param->disconnectinfo.cause = 31; /* normal unspecified */
2270 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2273 /* release call, disconnect isdn */
2275 new_state(EPOINT_STATE_OUT_DISCONNECT);
2276 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2277 SCPY(e_tone, cause);
2279 set_tone(portlist, cause);
2280 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2281 portlist = portlist->next;
2283 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2286 /* port MESSAGE_NOTIFY */
2287 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2289 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2291 struct lcr_msg *message;
2292 const char *logtext = "";
2295 /* signal to call tool */
2296 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);
2297 if (param->notifyinfo.notify) {
2298 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2301 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2302 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2303 case INFO_NOTIFY_REMOTE_HOLD:
2304 case INFO_NOTIFY_USER_SUSPENDED:
2305 /* tell call about it */
2306 if (ea_endpoint->ep_join_id) {
2307 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2308 message->param.audiopath = 0;
2309 message_put(message);
2313 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2314 case INFO_NOTIFY_USER_RESUMED:
2315 /* set volume of rx and tx */
2316 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2317 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2319 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2320 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2321 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2322 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2323 message_put(message);
2325 /* set current tone */
2327 set_tone(portlist, e_tone);
2328 /* tell call about it */
2329 if (ea_endpoint->ep_join_id) {
2330 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2331 message->param.audiopath = 1;
2332 message_put(message);
2337 /* get name of notify */
2338 switch(param->notifyinfo.notify) {
2343 logtext = "USER_SUSPENDED";
2346 logtext = "BEARER_SERVICE_CHANGED";
2349 logtext = "USER_RESUMED";
2352 logtext = "CONFERENCE_ESTABLISHED";
2355 logtext = "CONFERENCE_DISCONNECTED";
2358 logtext = "OTHER_PARTY_ADDED";
2361 logtext = "ISOLATED";
2364 logtext = "REATTACHED";
2367 logtext = "OTHER_PARTY_ISOLATED";
2370 logtext = "OTHER_PARTY_REATTACHED";
2373 logtext = "OTHER_PARTY_SPLIT";
2376 logtext = "OTHER_PARTY_DISCONNECTED";
2379 logtext = "CONFERENCE_FLOATING";
2382 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2385 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2388 logtext = "CALL_IS_A_WAITING_CALL";
2391 logtext = "DIVERSION_ACTIVATED";
2394 logtext = "RESERVED_CT_1";
2397 logtext = "RESERVED_CT_2";
2400 logtext = "REVERSE_CHARGING";
2403 logtext = "REMOTE_HOLD";
2406 logtext = "REMOTE_RETRIEVAL";
2409 logtext = "CALL_IS_DIVERTING";
2412 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2417 /* notify call if available */
2418 if (ea_endpoint->ep_join_id) {
2419 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2420 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2421 message_put(message);
2426 /* port MESSAGE_FACILITY */
2427 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2429 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2431 struct lcr_msg *message;
2433 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2434 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2435 message_put(message);
2438 /* port MESSAGE_SUSPEND */
2439 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2440 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2442 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2444 /* epoint is now parked */
2445 ea_endpoint->ep_park = 1;
2446 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2447 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2449 /* remove port relation */
2450 ea_endpoint->free_portlist(portlist);
2453 /* port MESSAGE_RESUME */
2454 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2455 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2457 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2459 /* epoint is now resumed */
2460 ea_endpoint->ep_park = 0;
2465 /* port sends message to the endpoint
2467 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2469 struct port_list *portlist;
2471 portlist = ea_endpoint->ep_portlist;
2473 if (port_id == portlist->port_id)
2475 portlist = portlist->next;
2478 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);
2482 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2483 switch(message_type) {
2484 case MESSAGE_DATA: /* data from port */
2485 /* check if there is a call */
2486 if (!ea_endpoint->ep_join_id)
2488 /* continue if only one portlist */
2489 if (ea_endpoint->ep_portlist->next != NULL)
2491 /* forward message */
2492 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2495 case MESSAGE_TONE_EOF: /* tone is end of file */
2496 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2498 if (e_action->index == ACTION_VBOX_PLAY) {
2501 if (e_action->index == ACTION_EFI) {
2507 case MESSAGE_TONE_COUNTER: /* counter info received */
2508 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);
2510 if (e_action->index == ACTION_VBOX_PLAY) {
2511 e_vbox_counter = param->counter.current;
2512 if (param->counter.max >= 0)
2513 e_vbox_counter_max = param->counter.max;
2517 /* PORT sends SETUP message */
2519 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);
2520 if (e_state!=EPOINT_STATE_IDLE) {
2521 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2524 port_setup(portlist, message_type, param);
2527 /* PORT sends INFORMATION message */
2528 case MESSAGE_INFORMATION: /* additional digits received */
2529 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);
2530 port_information(portlist, message_type, param);
2533 /* PORT sends FACILITY message */
2534 case MESSAGE_FACILITY:
2535 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2536 port_facility(portlist, message_type, param);
2539 /* PORT sends DTMF message */
2540 case MESSAGE_DTMF: /* dtmf digits received */
2541 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);
2542 port_dtmf(portlist, message_type, param);
2545 /* PORT sends CRYPT message */
2546 case MESSAGE_CRYPT: /* crypt response received */
2547 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2548 port_crypt(portlist, message_type, param);
2551 /* PORT sends MORE message */
2552 case MESSAGE_OVERLAP:
2553 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);
2554 if (e_state != EPOINT_STATE_OUT_SETUP) {
2555 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);
2558 port_overlap(portlist, message_type, param);
2561 /* PORT sends PROCEEDING message */
2562 case MESSAGE_PROCEEDING: /* port is proceeding */
2563 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);
2564 if (e_state!=EPOINT_STATE_OUT_SETUP
2565 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2566 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);
2569 port_proceeding(portlist, message_type, param);
2572 /* PORT sends ALERTING message */
2573 case MESSAGE_ALERTING:
2574 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);
2575 if (e_state!=EPOINT_STATE_OUT_SETUP
2576 && e_state!=EPOINT_STATE_OUT_OVERLAP
2577 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2578 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);
2581 port_alerting(portlist, message_type, param);
2584 /* PORT sends CONNECT message */
2585 case MESSAGE_CONNECT:
2586 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);
2587 if (e_state!=EPOINT_STATE_OUT_SETUP
2588 && e_state!=EPOINT_STATE_OUT_OVERLAP
2589 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2590 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2591 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2594 port_connect(portlist, message_type, param);
2597 /* PORT sends DISCONNECT message */
2598 case MESSAGE_DISCONNECT: /* port is disconnected */
2599 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);
2600 port_disconnect_release(portlist, message_type, param);
2603 /* PORT sends a RELEASE message */
2604 case MESSAGE_RELEASE: /* port releases */
2605 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);
2606 /* portlist is release at port_disconnect_release, thanx Paul */
2607 port_disconnect_release(portlist, message_type, param);
2610 /* PORT sends a TIMEOUT message */
2611 case MESSAGE_TIMEOUT:
2612 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);
2613 port_timeout(portlist, message_type, param);
2614 break; /* release */
2616 /* PORT sends a NOTIFY message */
2617 case MESSAGE_NOTIFY:
2618 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);
2619 port_notify(portlist, message_type, param);
2622 /* PORT sends a SUSPEND message */
2623 case MESSAGE_SUSPEND:
2624 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);
2625 port_suspend(portlist, message_type, param);
2626 break; /* suspend */
2628 /* PORT sends a RESUME message */
2629 case MESSAGE_RESUME:
2630 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);
2631 port_resume(portlist, message_type, param);
2635 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2636 /* port assigns bchannel */
2637 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2638 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);
2639 /* only one port is expected to be connected to bchannel */
2640 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2641 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2647 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);
2650 /* Note: this endpoint may be destroyed, so we MUST return */
2654 /* messages from join
2656 /* join MESSAGE_CRYPT */
2657 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2659 switch(param->crypt.type) {
2660 /* message from remote port to "crypt manager" */
2661 case CU_ACTK_REQ: /* activate key-exchange */
2662 case CU_ACTS_REQ: /* activate shared key */
2663 case CU_DACT_REQ: /* deactivate */
2664 case CU_INFO_REQ: /* request last info message */
2665 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2668 /* message from "crypt manager" to user */
2669 case CU_ACTK_CONF: /* key-echange done */
2670 case CU_ACTS_CONF: /* shared key done */
2671 case CU_DACT_CONF: /* deactivated */
2672 case CU_DACT_IND: /* deactivated */
2673 case CU_ERROR_IND: /* receive error message */
2674 case CU_INFO_IND: /* receive info message */
2675 case CU_INFO_CONF: /* receive info message */
2676 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2680 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);
2684 /* join MESSAGE_INFORMATION */
2685 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2687 struct lcr_msg *message;
2692 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2693 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2694 message_put(message);
2695 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2696 portlist = portlist->next;
2700 /* join MESSAGE_FACILITY */
2701 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2703 struct lcr_msg *message;
2705 if (!e_ext.facility && e_ext.number[0]) {
2710 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2711 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2712 message_put(message);
2713 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2714 portlist = portlist->next;
2718 /* join MESSAGE_MORE */
2719 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2721 struct lcr_msg *message;
2723 new_state(EPOINT_STATE_IN_OVERLAP);
2726 if (e_join_pattern && e_ext.own_setup) {
2727 /* disconnect audio */
2728 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2729 message->param.audiopath = 0;
2730 message_put(message);
2732 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2733 if (e_dialinginfo.id[0])
2734 set_tone(portlist, "dialing");
2736 set_tone(portlist, "dialtone");
2739 if (e_dialinginfo.id[0]) {
2740 set_tone(portlist, "dialing");
2742 if (e_ext.number[0])
2743 set_tone(portlist, "dialpbx");
2745 set_tone(portlist, "dialtone");
2749 /* join MESSAGE_PROCEEDING */
2750 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2752 struct lcr_msg *message;
2754 new_state(EPOINT_STATE_IN_PROCEEDING);
2756 /* own proceeding tone */
2757 if (e_join_pattern) {
2758 /* connect / disconnect audio */
2759 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2760 if (e_ext.own_proceeding)
2761 message->param.audiopath = 0;
2763 message->param.audiopath = 1;
2764 message_put(message);
2766 // UCPY(e_join_tone, "proceeding");
2768 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2769 message_put(message);
2770 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2772 set_tone(portlist, "proceeding");
2775 /* join MESSAGE_ALERTING */
2776 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2778 struct lcr_msg *message;
2780 new_state(EPOINT_STATE_IN_ALERTING);
2782 /* own alerting tone */
2783 if (e_join_pattern) {
2784 /* connect / disconnect audio */
2785 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2786 if (e_ext.own_alerting)
2787 message->param.audiopath = 0;
2789 message->param.audiopath = 1;
2790 message_put(message);
2793 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2794 message_put(message);
2795 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2797 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2798 set_tone(portlist, "ringing");
2801 if (e_ext.number[0])
2802 set_tone(portlist, "ringpbx");
2804 set_tone(portlist, "ringing");
2806 if (e_ext.number[0])
2807 e_dtmf = 1; /* allow dtmf */
2810 /* join MESSAGE_CONNECT */
2811 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2813 struct lcr_msg *message;
2815 new_state(EPOINT_STATE_CONNECT);
2816 // UCPY(e_join_tone, "");
2818 if (e_ext.number[0])
2819 e_dtmf = 1; /* allow dtmf */
2822 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2824 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2825 memcpy(&message->param, param, sizeof(union parameter));
2827 /* screen clip if prefix is required */
2828 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2829 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2830 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2831 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2834 /* use internal caller id */
2835 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2836 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2837 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2840 /* handle restricted caller ids */
2841 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);
2842 /* display callerid if desired for extension */
2843 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));
2845 /* use conp, if enabld */
2846 // if (!e_ext.centrex)
2847 // message->param.connectinfo.name[0] = '\0';
2850 message_put(message);
2851 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2853 set_tone(portlist, NULL);
2855 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2856 message->param.audiopath = 1;
2857 message_put(message);
2861 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2862 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2865 struct lcr_msg *message;
2866 struct port_list *portlist = NULL;
2869 /* be sure that we are active */
2871 e_tx_state = NOTIFY_STATE_ACTIVE;
2873 /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
2874 if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2875 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2877 /* set time for power dialing */
2878 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
2881 /* set redial tone */
2882 if (ea_endpoint->ep_portlist) {
2885 set_tone(ea_endpoint->ep_portlist, "redial");
2886 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);
2887 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2888 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2889 new_state(EPOINT_STATE_IN_PROCEEDING);
2890 if (ea_endpoint->ep_portlist) {
2891 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2892 message_put(message);
2893 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2895 /* caused the error, that the first knock sound was not there */
2896 /* set_tone(portlist, "proceeding"); */
2898 /* send display of powerdialing */
2899 if (e_ext.display_dialing) {
2900 portlist = ea_endpoint->ep_portlist;
2902 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2904 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2906 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2907 message_put(message);
2908 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2909 portlist = portlist->next;
2918 if ((e_state!=EPOINT_STATE_CONNECT
2919 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2920 && e_state!=EPOINT_STATE_IN_OVERLAP
2921 && e_state!=EPOINT_STATE_IN_PROCEEDING
2922 && e_state!=EPOINT_STATE_IN_ALERTING)
2923 || !ea_endpoint->ep_portlist) { /* or no port */
2924 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2925 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */
2926 return; /* must exit here */
2929 if (!e_join_cause) {
2930 e_join_cause = param->disconnectinfo.cause;
2931 e_join_location = param->disconnectinfo.location;
2934 /* on release we need the audio again! */
2935 if (message_type == MESSAGE_RELEASE) {
2937 ea_endpoint->ep_join_id = 0;
2939 /* disconnect and select tone */
2940 new_state(EPOINT_STATE_OUT_DISCONNECT);
2941 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2942 /* if own_cause, we must release the join */
2943 if (e_ext.own_cause /* own cause */
2944 || !e_join_pattern) { /* no patterns */
2945 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);
2946 if (message_type != MESSAGE_RELEASE)
2947 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2949 } else { /* else we enable audio */
2950 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2951 message->param.audiopath = 1;
2952 message_put(message);
2954 /* send disconnect message */
2955 SCPY(e_tone, cause);
2956 portlist = ea_endpoint->ep_portlist;
2958 set_tone(portlist, cause);
2959 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2960 portlist = portlist->next;
2964 /* join MESSAGE_SETUP */
2965 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2967 struct lcr_msg *message;
2968 // struct interface *interface;
2970 /* if we already in setup state, we just update the dialing with new digits */
2971 if (e_state == EPOINT_STATE_OUT_SETUP
2972 || e_state == EPOINT_STATE_OUT_OVERLAP) {
2973 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
2974 /* if digits changed, what we have already dialed */
2975 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
2976 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);
2977 /* release all ports */
2978 while((portlist = ea_endpoint->ep_portlist)) {
2979 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2980 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2981 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2982 message_put(message);
2983 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2984 ea_endpoint->free_portlist(portlist);
2987 /* disconnect audio */
2988 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2989 message->param.audiopath = 0;
2990 message_put(message);
2992 /* get dialing info */
2993 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
2994 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2995 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
2996 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
2997 new_state(EPOINT_STATE_OUT_OVERLAP);
3000 e_redial = now_d + 1; /* set redial one second in the future */
3003 /* if we have a pending redial, so we just adjust the dialing number */
3005 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);
3006 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3009 if (!ea_endpoint->ep_portlist) {
3010 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3012 if (ea_endpoint->ep_portlist->next) {
3013 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3015 if (e_state == EPOINT_STATE_OUT_SETUP) {
3017 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);
3018 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3021 /* get what we have not dialed yet */
3022 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));
3023 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3024 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3025 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3026 message_put(message);
3027 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3029 /* always store what we have dialed or queued */
3030 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3034 if (e_state != EPOINT_STATE_IDLE) {
3035 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3038 /* if an internal extension is dialed, copy that number */
3039 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3040 SCPY(e_ext.number, param->setup.dialinginfo.id);
3041 /* if an internal extension is dialed, get extension's info about caller */
3042 if (e_ext.number[0]) {
3043 if (!read_extension(&e_ext, e_ext.number)) {
3044 e_ext.number[0] = '\0';
3045 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3049 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3050 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3051 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3052 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3054 /* process (voice over) data calls */
3055 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3056 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3057 memset(&e_capainfo, 0, sizeof(e_capainfo));
3058 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3059 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3060 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3063 new_state(EPOINT_STATE_OUT_SETUP);
3064 /* call special setup routine */
3068 /* join MESSAGE_mISDNSIGNAL */
3069 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3071 struct lcr_msg *message;
3074 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3075 memcpy(&message->param, param, sizeof(union parameter));
3076 message_put(message);
3077 portlist = portlist->next;
3081 /* join MESSAGE_NOTIFY */
3082 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3084 struct lcr_msg *message;
3087 if (param->notifyinfo.notify) {
3088 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3089 // /* if notification was generated locally, we turn hold music on/off */
3090 // if (param->notifyinfo.local)
3091 // 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)
3095 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3096 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3098 set_tone(portlist, "");
3099 portlist = portlist->next;
3102 portlist = ea_endpoint->ep_portlist;
3107 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3109 set_tone(portlist, "hold");
3110 portlist = portlist->next;
3112 portlist = ea_endpoint->ep_portlist;
3117 /* save new state */
3118 e_tx_state = new_state;
3121 /* notify port(s) about it */
3123 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3124 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3125 /* handle restricted caller ids */
3126 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3127 /* display callerid if desired for extension */
3128 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));
3129 message_put(message);
3130 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3131 portlist = portlist->next;
3135 /* JOIN sends messages to the endpoint
3137 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3139 struct port_list *portlist;
3140 struct lcr_msg *message;
3143 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3147 portlist = ea_endpoint->ep_portlist;
3149 /* send MESSAGE_DATA to port */
3150 if (message_type == MESSAGE_DATA) {
3151 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3152 /* skip if no port relation */
3155 /* skip if more than one port relation */
3158 /* forward audio data to port */
3159 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3164 // 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);
3165 switch(message_type) {
3166 /* JOIN SENDS TONE message */
3168 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);
3169 set_tone(portlist, param->tone.name);
3172 /* JOIN SENDS CRYPT message */
3174 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);
3175 join_crypt(portlist, message_type, param);
3178 /* JOIN sends INFORMATION message */
3179 case MESSAGE_INFORMATION:
3180 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);
3181 join_information(portlist, message_type, param);
3184 /* JOIN sends FACILITY message */
3185 case MESSAGE_FACILITY:
3186 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);
3187 join_facility(portlist, message_type, param);
3190 /* JOIN sends OVERLAP message */
3191 case MESSAGE_OVERLAP:
3192 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);
3193 if (e_state!=EPOINT_STATE_IN_SETUP
3194 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3195 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3198 join_overlap(portlist, message_type, param);
3201 /* JOIN sends PROCEEDING message */
3202 case MESSAGE_PROCEEDING:
3203 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);
3204 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3205 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3208 join_proceeding(portlist, message_type, param);
3211 /* JOIN sends ALERTING message */
3212 case MESSAGE_ALERTING:
3213 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);
3214 if (e_state!=EPOINT_STATE_IN_OVERLAP
3215 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3216 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3219 join_alerting(portlist, message_type, param);
3222 /* JOIN sends CONNECT message */
3223 case MESSAGE_CONNECT:
3224 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);
3225 if (e_state!=EPOINT_STATE_IN_OVERLAP
3226 && e_state!=EPOINT_STATE_IN_PROCEEDING
3227 && e_state!=EPOINT_STATE_IN_ALERTING) {
3228 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3231 join_connect(portlist, message_type, param);
3234 /* JOIN sends DISCONNECT/RELEASE message */
3235 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3236 case MESSAGE_RELEASE: /* JOIN releases */
3237 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);
3238 join_disconnect_release(message_type, param);
3241 /* JOIN sends SETUP message */
3243 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);
3244 join_setup(portlist, message_type, param);
3247 /* JOIN sends special mISDNSIGNAL message */
3248 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3249 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);
3250 join_mISDNsignal(portlist, message_type, param);
3254 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3255 /* JOIN requests bchannel */
3256 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3257 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);
3258 /* only one port is expected to be connected to bchannel */
3265 set_tone(portlist, NULL);
3266 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3267 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3271 /* JOIN has pattern available */
3272 case MESSAGE_PATTERN: /* indicating pattern available */
3273 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);
3274 if (!e_join_pattern) {
3275 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3279 set_tone(portlist, NULL);
3280 portlist = portlist->next;
3282 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3283 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3284 message->param.audiopath = 1;
3285 message_put(message);
3289 /* JOIN has no pattern available */
3290 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3291 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);
3292 if (e_join_pattern) {
3293 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3295 /* disconnect our audio tx and rx */
3296 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3297 message->param.audiopath = 0;
3298 message_put(message);
3303 /* JOIN (dunno at the moment) */
3304 case MESSAGE_REMOTE_AUDIO:
3305 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);
3306 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3307 message->param.audiopath = param->channel;
3308 message_put(message);
3312 /* JOIN sends a notify message */
3313 case MESSAGE_NOTIFY:
3314 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);
3315 join_notify(portlist, message_type, param);
3318 /* JOIN wants keypad / dtmf */
3319 case MESSAGE_ENABLEKEYPAD:
3320 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);
3323 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3328 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);
3333 /* pick_join will connect the first incoming call found. the endpoint
3334 * will receivce a MESSAGE_CONNECT.
3336 int match_list(char *list, char *item)
3338 char *end, *next = NULL;
3340 /* no list make matching */
3345 /* eliminate white spaces */
3346 while (*list <= ' ')
3352 /* if end of list is reached, we return */
3353 if (list[0] == '\0')
3355 /* if we have more than one entry (left) */
3356 if ((end = strchr(list, ',')))
3359 next = end = strchr(list, '\0');
3360 while (*(end-1) <= ' ')
3362 /* if string part matches item */
3363 if (!strncmp(list, item, end-list))
3369 void EndpointAppPBX::pick_join(char *extensions)
3371 struct lcr_msg *message;
3372 struct port_list *portlist;
3374 class EndpointAppPBX *eapp, *found;
3376 class JoinPBX *joinpbx;
3377 struct join_relation *relation;
3380 /* find an endpoint that is ringing internally or vbox with higher priority */
3383 eapp = apppbx_first;
3385 if (eapp!=this && ea_endpoint->ep_portlist) {
3386 portlist = eapp->ea_endpoint->ep_portlist;
3388 if ((port = find_port_id(portlist->port_id))) {
3389 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3390 if (match_list(extensions, eapp->e_ext.number)) {
3396 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3397 && port->p_state==PORT_STATE_OUT_ALERTING)
3398 if (match_list(extensions, eapp->e_ext.number)) {
3402 portlist = portlist->next;
3410 /* if no endpoint found */
3412 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);
3414 set_tone(ea_endpoint->ep_portlist, "cause_10");
3415 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3416 new_state(EPOINT_STATE_OUT_DISCONNECT);
3421 if (ea_endpoint->ep_join_id) {
3422 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3425 if (!eapp->ea_endpoint->ep_join_id) {
3426 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3429 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3431 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3434 if (join->j_type != JOIN_TYPE_PBX) {
3435 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3438 joinpbx = (class JoinPBX *)join;
3439 relation = joinpbx->j_relation;
3441 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3444 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3445 relation = relation->next;
3447 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3452 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3454 if (options.deb & DEBUG_EPOINT) {
3455 class Join *debug_c = join_first;
3456 class Endpoint *debug_e = epoint_first;
3457 class Port *debug_p = port_first;
3459 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3461 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3463 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3464 debug_c = debug_c->next;
3466 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3468 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3469 debug_e = debug_e->next;
3471 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3473 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3474 debug_p = debug_p->next;
3479 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3480 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3481 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3483 /* connnecting our endpoint */
3484 new_state(EPOINT_STATE_CONNECT);
3485 if (e_ext.number[0])
3487 set_tone(ea_endpoint->ep_portlist, NULL);
3489 /* now we send a release to the ringing endpoint */
3490 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3491 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3492 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3493 message_put(message);
3495 /* we send a connect to the join with our caller id */
3496 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3497 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3498 message->param.connectinfo.present = e_callerinfo.present;
3499 message->param.connectinfo.screen = e_callerinfo.screen;
3500 message->param.connectinfo.itype = e_callerinfo.itype;
3501 message->param.connectinfo.ntype = e_callerinfo.ntype;
3502 message_put(message);
3504 /* we send a connect to our port with the remote callerid */
3505 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3506 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3507 message->param.connectinfo.present = eapp->e_callerinfo.present;
3508 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3509 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3510 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3511 /* handle restricted caller ids */
3512 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);
3513 /* display callerid if desired for extension */
3514 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));
3515 message_put(message);
3517 /* we send a connect to the audio path (not for vbox) */
3518 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3519 message->param.audiopath = 1;
3520 message_put(message);
3522 /* beeing paranoid, we make call update */
3523 joinpbx->j_updatebridge = 1;
3525 if (options.deb & DEBUG_EPOINT) {
3526 class Join *debug_c = join_first;
3527 class Endpoint *debug_e = epoint_first;
3528 class Port *debug_p = port_first;
3530 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3532 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3534 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3535 debug_c = debug_c->next;
3537 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3539 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3540 debug_e = debug_e->next;
3542 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3544 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3545 debug_p = debug_p->next;
3551 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3553 void EndpointAppPBX::join_join(void)
3555 struct lcr_msg *message;
3556 struct join_relation *our_relation, *other_relation;
3557 struct join_relation **our_relation_pointer, **other_relation_pointer;
3558 class Join *our_join, *other_join;
3559 class JoinPBX *our_joinpbx, *other_joinpbx;
3560 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3561 class Port *our_port, *other_port;
3562 class Pdss1 *our_pdss1, *other_pdss1;
3564 /* are we a candidate to join a join? */
3565 our_join = find_join_id(ea_endpoint->ep_join_id);
3567 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3570 if (our_join->j_type != JOIN_TYPE_PBX) {
3571 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3574 our_joinpbx = (class JoinPBX *)our_join;
3575 if (!ea_endpoint->ep_portlist) {
3576 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3579 if (!e_ext.number[0]) {
3580 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3583 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3585 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3588 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3589 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3592 our_pdss1 = (class Pdss1 *)our_port;
3594 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3595 other_eapp = apppbx_first;
3597 if (other_eapp == this) {
3598 other_eapp = other_eapp->next;
3601 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);
3602 if (other_eapp->e_ext.number[0] /* has terminal */
3603 && other_eapp->ea_endpoint->ep_portlist /* has port */
3604 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3605 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3606 if (other_port) { /* port still exists */
3607 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3608 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3609 other_pdss1 = (class Pdss1 *)other_port;
3610 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);
3611 if (other_pdss1->p_m_hold /* port is on hold */
3612 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3613 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3616 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3619 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3622 other_eapp = other_eapp->next;
3625 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3628 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3630 /* if we have the same join */
3631 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3632 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3635 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3637 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3640 if (other_join->j_type != JOIN_TYPE_PBX) {
3641 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3644 other_joinpbx = (class JoinPBX *)other_join;
3645 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3646 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3650 /* remove relation to endpoint for join on hold */
3651 other_relation = other_joinpbx->j_relation;
3652 other_relation_pointer = &other_joinpbx->j_relation;
3653 while(other_relation) {
3654 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3655 /* detach other endpoint on hold */
3656 *other_relation_pointer = other_relation->next;
3657 FREE(other_relation, sizeof(struct join_relation));
3659 other_relation = *other_relation_pointer;
3660 other_eapp->ea_endpoint->ep_join_id = 0;
3664 /* change join/hold pointer of endpoint to the new join */
3665 temp_epoint = find_epoint_id(other_relation->epoint_id);
3667 if (temp_epoint->ep_join_id == other_join->j_serial)
3668 temp_epoint->ep_join_id = our_join->j_serial;
3671 other_relation_pointer = &other_relation->next;
3672 other_relation = other_relation->next;
3674 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3676 /* join call relations */
3677 our_relation = our_joinpbx->j_relation;
3678 our_relation_pointer = &our_joinpbx->j_relation;
3679 while(our_relation) {
3680 our_relation_pointer = &our_relation->next;
3681 our_relation = our_relation->next;
3683 *our_relation_pointer = other_joinpbx->j_relation;
3684 other_joinpbx->j_relation = NULL;
3685 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3687 /* release endpoint on hold */
3688 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3689 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3690 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3691 message_put(message);
3693 /* if we are not a partyline, we get partyline state from other join */
3694 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3696 /* remove empty join */
3698 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3700 /* mixer must update */
3701 our_joinpbx->j_updatebridge = 1; /* update mixer flag */
3703 /* we send a retrieve to that endpoint */
3704 // mixer will update the hold-state of the join and send it to the endpoints is changes
3708 /* check if we have an external call
3709 * this is used to check for encryption ability
3711 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3713 struct join_relation *relation;
3715 class JoinPBX *joinpbx;
3716 class Endpoint *epoint;
3718 /* some paranoia check */
3719 if (!ea_endpoint->ep_portlist) {
3720 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3721 *errstr = "No Call";
3724 if (!e_ext.number[0]) {
3725 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3726 *errstr = "No Call";
3730 /* check if we have a join with 2 parties */
3731 join = find_join_id(ea_endpoint->ep_join_id);
3733 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3734 *errstr = "No Call";
3737 if (join->j_type != JOIN_TYPE_PBX) {
3738 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3739 *errstr = "No PBX Call";
3742 joinpbx = (class JoinPBX *)join;
3743 relation = joinpbx->j_relation;
3745 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3746 *errstr = "No Call";
3749 if (!relation->next) {
3750 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3751 *errstr = "No Call";
3754 if (relation->next->next) {
3755 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3756 *errstr = "Err: Conference";
3759 if (relation->epoint_id == ea_endpoint->ep_serial) {
3760 relation = relation->next;
3761 if (relation->epoint_id == ea_endpoint->ep_serial) {
3762 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3763 *errstr = "Software Error";
3768 /* check remote port for external call */
3769 epoint = find_epoint_id(relation->epoint_id);
3771 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3772 *errstr = "No Call";
3775 if (!epoint->ep_portlist) {
3776 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3777 *errstr = "No Call";
3780 *port = find_port_id(epoint->ep_portlist->port_id);
3782 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3783 *errstr = "No Call";
3786 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3787 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3788 *errstr = "No Ext Call";
3791 if ((*port)->p_state != PORT_STATE_CONNECT) {
3792 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3793 *errstr = "No Ext Connect";
3799 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3801 const char *logtext = "unknown";
3804 switch(message_type) {
3806 trace_header("SETUP", dir);
3807 if (dir == DIRECTION_OUT)
3808 add_trace("to", NULL, "CH(%lu)", port_id);
3809 if (dir == DIRECTION_IN)
3810 add_trace("from", NULL, "CH(%lu)", port_id);
3811 if (param->setup.callerinfo.extension[0])
3812 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3813 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3814 switch(param->setup.callerinfo.present) {
3815 case INFO_PRESENT_RESTRICTED:
3816 add_trace("caller id", "present", "restricted");
3818 case INFO_PRESENT_ALLOWED:
3819 add_trace("caller id", "present", "allowed");
3822 add_trace("caller id", "present", "not available");
3824 if (param->setup.callerinfo.ntype2) {
3825 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3826 switch(param->setup.callerinfo.present) {
3827 case INFO_PRESENT_RESTRICTED:
3828 add_trace("caller id2", "present", "restricted");
3830 case INFO_PRESENT_ALLOWED:
3831 add_trace("caller id2", "present", "allowed");
3834 add_trace("caller id2", "present", "not available");
3837 if (param->setup.redirinfo.id[0]) {
3838 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3839 switch(param->setup.redirinfo.present) {
3840 case INFO_PRESENT_RESTRICTED:
3841 add_trace("redir'ing", "present", "restricted");
3843 case INFO_PRESENT_ALLOWED:
3844 add_trace("redir'ing", "present", "allowed");
3847 add_trace("redir'ing", "present", "not available");
3850 if (param->setup.dialinginfo.id[0])
3851 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3852 if (param->setup.dialinginfo.keypad[0])
3853 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3854 if (param->setup.dialinginfo.display[0])
3855 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3856 if (param->setup.dialinginfo.sending_complete)
3857 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3861 case MESSAGE_OVERLAP:
3862 trace_header("SETUP ACKNOWLEDGE", dir);
3863 if (dir == DIRECTION_OUT)
3864 add_trace("to", NULL, "CH(%lu)", port_id);
3865 if (dir == DIRECTION_IN)
3866 add_trace("from", NULL, "CH(%lu)", port_id);
3870 case MESSAGE_PROCEEDING:
3871 trace_header("PROCEEDING", dir);
3872 if (dir == DIRECTION_OUT)
3873 add_trace("to", NULL, "CH(%lu)", port_id);
3874 if (dir == DIRECTION_IN)
3875 add_trace("from", NULL, "CH(%lu)", port_id);
3879 case MESSAGE_ALERTING:
3880 trace_header("ALERTING", dir);
3881 if (dir == DIRECTION_OUT)
3882 add_trace("to", NULL, "CH(%lu)", port_id);
3883 if (dir == DIRECTION_IN)
3884 add_trace("from", NULL, "CH(%lu)", port_id);
3888 case MESSAGE_CONNECT:
3889 trace_header("CONNECT", dir);
3890 if (dir == DIRECTION_OUT)
3891 add_trace("to", NULL, "CH(%lu)", port_id);
3892 if (dir == DIRECTION_IN)
3893 add_trace("from", NULL, "CH(%lu)", port_id);
3894 if (param->connectinfo.extension[0])
3895 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3896 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3897 switch(param->connectinfo.present) {
3898 case INFO_PRESENT_RESTRICTED:
3899 add_trace("connect id", "present", "restricted");
3901 case INFO_PRESENT_ALLOWED:
3902 add_trace("connect id", "present", "allowed");
3905 add_trace("connect id", "present", "not available");
3907 if (param->connectinfo.display[0])
3908 add_trace("display", NULL, "%s", param->connectinfo.display);
3912 case MESSAGE_DISCONNECT:
3913 case MESSAGE_RELEASE:
3914 if (message_type == MESSAGE_DISCONNECT)
3915 trace_header("DISCONNECT", dir);
3917 trace_header("RELEASE", dir);
3918 if (dir == DIRECTION_OUT)
3919 add_trace("to", NULL, "CH(%lu)", port_id);
3920 if (dir == DIRECTION_IN)
3921 add_trace("from", NULL, "CH(%lu)", port_id);
3922 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3923 switch(param->disconnectinfo.location) {
3925 add_trace("cause", "location", "0-User");
3927 case LOCATION_PRIVATE_LOCAL:
3928 add_trace("cause", "location", "1-Local-PBX");
3930 case LOCATION_PUBLIC_LOCAL:
3931 add_trace("cause", "location", "2-Local-Exchange");
3933 case LOCATION_TRANSIT:
3934 add_trace("cause", "location", "3-Transit");
3936 case LOCATION_PUBLIC_REMOTE:
3937 add_trace("cause", "location", "4-Remote-Exchange");
3939 case LOCATION_PRIVATE_REMOTE:
3940 add_trace("cause", "location", "5-Remote-PBX");
3942 case LOCATION_INTERNATIONAL:
3943 add_trace("cause", "location", "7-International-Exchange");
3945 case LOCATION_BEYOND:
3946 add_trace("cause", "location", "10-Beyond-Interworking");
3949 add_trace("cause", "location", "%d", param->disconnectinfo.location);
3951 if (param->disconnectinfo.display[0])
3952 add_trace("display", NULL, "%s", param->disconnectinfo.display);
3956 case MESSAGE_NOTIFY:
3957 switch(param->notifyinfo.notify) {
3962 logtext = "USER_SUSPENDED";
3965 logtext = "BEARER_SERVICE_CHANGED";
3968 logtext = "USER_RESUMED";
3971 logtext = "CONFERENCE_ESTABLISHED";
3974 logtext = "CONFERENCE_DISCONNECTED";
3977 logtext = "OTHER_PARTY_ADDED";
3980 logtext = "ISOLATED";
3983 logtext = "REATTACHED";
3986 logtext = "OTHER_PARTY_ISOLATED";
3989 logtext = "OTHER_PARTY_REATTACHED";
3992 logtext = "OTHER_PARTY_SPLIT";
3995 logtext = "OTHER_PARTY_DISCONNECTED";
3998 logtext = "CONFERENCE_FLOATING";
4001 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4004 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4007 logtext = "CALL_IS_A_WAITING_CALL";
4010 logtext = "DIVERSION_ACTIVATED";
4013 logtext = "RESERVED_CT_1";
4016 logtext = "RESERVED_CT_2";
4019 logtext = "REVERSE_CHARGING";
4022 logtext = "REMOTE_HOLD";
4025 logtext = "REMOTE_RETRIEVAL";
4028 logtext = "CALL_IS_DIVERTING";
4031 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4035 trace_header("NOTIFY", dir);
4036 if (dir == DIRECTION_OUT)
4037 add_trace("to", NULL, "CH(%lu)", port_id);
4038 if (dir == DIRECTION_IN)
4039 add_trace("from", NULL, "CH(%lu)", port_id);
4040 if (param->notifyinfo.notify)
4041 add_trace("indicator", NULL, "%s", logtext);
4042 if (param->notifyinfo.id[0]) {
4043 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4044 switch(param->notifyinfo.present) {
4045 case INFO_PRESENT_RESTRICTED:
4046 add_trace("redir'on", "present", "restricted");
4048 case INFO_PRESENT_ALLOWED:
4049 add_trace("redir'on", "present", "allowed");
4052 add_trace("redir'on", "present", "not available");
4055 if (param->notifyinfo.display[0])
4056 add_trace("display", NULL, "%s", param->notifyinfo.display);
4060 case MESSAGE_INFORMATION:
4061 trace_header("INFORMATION", dir);
4062 if (dir == DIRECTION_OUT)
4063 add_trace("to", NULL, "CH(%lu)", port_id);
4064 if (dir == DIRECTION_IN)
4065 add_trace("from", NULL, "CH(%lu)", port_id);
4066 if (param->information.id[0])
4067 add_trace("dialing", NULL, "%s", param->information.id);
4068 if (param->information.display[0])
4069 add_trace("display", NULL, "%s", param->information.display);
4070 if (param->information.sending_complete)
4071 add_trace("complete", NULL, "true", param->information.sending_complete);
4075 case MESSAGE_FACILITY:
4076 trace_header("FACILITY", dir);
4077 if (dir == DIRECTION_OUT)
4078 add_trace("to", NULL, "CH(%lu)", port_id);
4079 if (dir == DIRECTION_IN)
4080 add_trace("from", NULL, "CH(%lu)", port_id);
4085 trace_header("TONE", dir);
4086 if (dir == DIRECTION_OUT)
4087 add_trace("to", NULL, "CH(%lu)", port_id);
4088 if (dir == DIRECTION_IN)
4089 add_trace("from", NULL, "CH(%lu)", port_id);
4090 if (param->tone.name[0]) {
4091 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4092 add_trace("name", NULL, "%s", param->tone.name);
4094 add_trace("off", NULL, NULL);
4098 case MESSAGE_SUSPEND:
4099 case MESSAGE_RESUME:
4100 if (message_type == MESSAGE_SUSPEND)
4101 trace_header("SUSPEND", dir);
4103 trace_header("RESUME", dir);
4104 if (dir == DIRECTION_OUT)
4105 add_trace("to", NULL, "CH(%lu)", port_id);
4106 if (dir == DIRECTION_IN)
4107 add_trace("from", NULL, "CH(%lu)", port_id);
4108 if (param->parkinfo.len)
4109 add_trace("length", NULL, "%d", param->parkinfo.len);
4114 case MESSAGE_BCHANNEL:
4115 trace_header("BCHANNEL", dir);
4116 switch(param->bchannel.type) {
4117 case BCHANNEL_REQUEST:
4118 add_trace("type", NULL, "request");
4120 case BCHANNEL_ASSIGN:
4121 add_trace("type", NULL, "assign");
4123 case BCHANNEL_ASSIGN_ACK:
4124 add_trace("type", NULL, "assign_ack");
4126 case BCHANNEL_REMOVE:
4127 add_trace("type", NULL, "remove");
4129 case BCHANNEL_REMOVE_ACK:
4130 add_trace("type", NULL, "remove_ack");
4133 if (param->bchannel.addr)
4134 add_trace("address", NULL, "%x", param->bchannel.addr);
4140 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4144 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4146 struct lcr_msg *message;
4150 if (!portlist->port_id)
4153 if (!e_connectedmode) {
4154 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4155 message->param.disconnectinfo.cause = cause;
4156 message->param.disconnectinfo.location = location;
4158 SCPY(message->param.disconnectinfo.display, display);
4160 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4162 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4164 SCPY(message->param.notifyinfo.display, display);
4166 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4168 message_put(message);
4169 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);