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 */
651 selchannel = ifport->out_channel;
653 switch(selchannel->channel) {
654 case CHANNEL_FREE: /* free channel */
655 if (mISDNport->b_reserved >= mISDNport->b_num)
656 break; /* all channel in use or reserverd */
659 while(i < mISDNport->b_num) {
660 if (mISDNport->b_port[i] == NULL) {
661 *channel = i+1+(i>=15);
662 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
663 add_trace("port", NULL, "%d", ifport->portnum);
664 add_trace("position", NULL, "%d", index);
665 add_trace("channel", NULL, "%d", *channel);
673 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
674 add_trace("port", NULL, "%d", ifport->portnum);
675 add_trace("position", NULL, "%d", index);
679 case CHANNEL_ANY: /* don't ask for channel */
680 if (mISDNport->b_reserved >= mISDNport->b_num) {
681 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
682 add_trace("port", NULL, "%d", ifport->portnum);
683 add_trace("position", NULL, "%d", index);
684 add_trace("total", NULL, "%d", mISDNport->b_num);
685 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
687 break; /* all channel in use or reserverd */
689 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
690 add_trace("port", NULL, "%d", ifport->portnum);
691 add_trace("position", NULL, "%d", index);
693 *channel = CHANNEL_ANY;
696 case CHANNEL_NO: /* call waiting */
697 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
698 add_trace("port", NULL, "%d", ifport->portnum);
699 add_trace("position", NULL, "%d", index);
701 *channel = CHANNEL_NO;
705 if (selchannel->channel<1 || selchannel->channel==16) {
706 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
707 add_trace("port", NULL, "%d", ifport->portnum);
708 add_trace("position", NULL, "%d", index);
709 add_trace("channel", NULL, "%d", selchannel->channel);
711 break; /* invalid channels */
713 i = selchannel->channel-1-(selchannel->channel>=17);
714 if (i >= mISDNport->b_num) {
715 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
716 add_trace("port", NULL, "%d", ifport->portnum);
717 add_trace("position", NULL, "%d", index);
718 add_trace("channel", NULL, "%d", selchannel->channel);
719 add_trace("channels", NULL, "%d", mISDNport->b_num);
721 break; /* channel not in port */
723 if (mISDNport->b_port[i] == NULL) {
724 *channel = selchannel->channel;
725 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
726 add_trace("port", NULL, "%d", ifport->portnum);
727 add_trace("position", NULL, "%d", index);
728 add_trace("channel", NULL, "%d", *channel);
735 break; /* found channel */
736 selchannel = selchannel->next;
739 /* if channel was found, return mISDNport and channel */
741 /* setting next port to start next time */
742 if (interface->hunt == HUNT_ROUNDROBIN) {
746 interface->hunt_next = index;
752 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
753 add_trace("port", NULL, "%d", ifport->portnum);
754 add_trace("position", NULL, "%d", index);
758 /* go next port, until all ports are checked */
760 ifport = ifport->next;
763 ifport = interface->ifport;
765 if (ifport != ifport_start)
769 interface = interface->next;
773 return(NULL); /* no port found */
776 /* outgoing setup to port(s)
777 * ports will be created and a setup is sent if everything is ok. otherwhise
778 * the endpoint is destroyed.
780 void EndpointAppPBX::out_setup(void)
782 struct dialing_info dialinginfo;
784 struct port_list *portlist;
785 struct lcr_msg *message;
787 int cause = CAUSE_RESSOURCEUNAVAIL;
790 struct mISDNport *mISDNport;
793 class EndpointAppPBX *atemp;
794 // char allowed_ports[256];
796 char ifname[sizeof(e_ext.interfaces)],
798 struct port_settings port_settings;
801 int mode = B_MODE_TRANSPARENT;
803 /* set bchannel mode */
804 mode = e_capainfo.source_mode;
806 /* create settings for creating port */
807 memset(&port_settings, 0, sizeof(port_settings));
809 SCPY(port_settings.tones_dir, e_ext.tones_dir);
811 SCPY(port_settings.tones_dir, options.tones_dir);
812 port_settings.no_seconds = e_ext.no_seconds;
814 /* 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 */
816 /* check what dialinginfo.itype we got */
817 switch(e_dialinginfo.itype) {
818 /* *********************** call to extension or vbox */
819 case INFO_ITYPE_ISDN_EXTENSION:
820 /* check if we deny incoming calls when we use an extension */
821 if (e_ext.noknocking) {
822 atemp = apppbx_first;
825 if (!strcmp(atemp->e_ext.number, e_ext.number))
830 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
831 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYSPE_ join, port */
832 return; /* must exit here */
835 /* FALL THROUGH !!!! */
836 case INFO_ITYPE_VBOX:
837 /* get dialed extension's info */
838 // SCPY(exten, e_dialinginfo.id);
839 // if (strchr(exten, ','))
840 // *strchr(exten, ',') = '\0';
841 // if (!read_extension(&e_ext, exten))
842 if (!read_extension(&e_ext, e_dialinginfo.id)) {
843 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
844 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
845 return; /* must exit here */
848 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
849 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
854 /* string from unconditional call forward (cfu) */
857 /* present to forwarded party */
858 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
859 e_callerinfo.present = INFO_PRESENT_ALLOWED;
861 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
865 /* string from busy call forward (cfb) */
868 class EndpointAppPBX *checkapp = apppbx_first;
870 if (checkapp != this) { /* any other endpoint except our own */
871 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
872 /* present to forwarded party */
873 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
874 e_callerinfo.present = INFO_PRESENT_ALLOWED;
876 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
880 checkapp = checkapp->next;
884 /* string from no-response call forward (cfnr) */
887 /* when cfnr is done, out_setup() will setup the call */
889 /* present to forwarded party */
890 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
891 e_callerinfo.present = INFO_PRESENT_ALLOWED;
895 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
896 e_cfnr_release = now + e_ext.cfnr_delay;
897 e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */
898 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);
902 /* call to all internal interfaces */
903 p = e_ext.interfaces;
904 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
907 while(*p!=',' && *p!='\0')
912 /* found interface */
913 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
914 /* hunt for mISDNport and create Port */
915 mISDNport = hunt_port(ifname, &channel);
917 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
918 add_trace("interface", NULL, "%s", ifname);
922 /* creating INTERNAL port */
923 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
925 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);
928 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
933 FATAL("No memory for Port instance\n");
934 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
935 memset(&dialinginfo, 0, sizeof(dialinginfo));
936 SCPY(dialinginfo.id, e_dialinginfo.id);
937 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
938 dialinginfo.ntype = e_dialinginfo.ntype;
939 /* create port_list relation */
940 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
942 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
944 goto check_anycall_intern;
947 if (e_callerinfo.id[0] && e_ext.display_name) {
948 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
950 SCPY(e_callerinfo.name, dirname);
952 // dss1 = (class Pdss1 *)port;
954 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
955 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
956 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
957 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
958 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
959 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
960 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
961 //terminal if (e_dialinginfo.id)
962 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
963 /* handle restricted caller ids */
964 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);
965 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);
966 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);
967 /* display callerid if desired for extension */
968 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));
969 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
970 /* use cnip, if enabld */
971 // if (!e_ext.centrex)
972 // message->param.setup.callerinfo.name[0] = '\0';
973 /* screen clip if prefix is required */
974 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
975 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
976 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
977 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
979 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
980 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
981 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
982 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
984 /* use internal caller id */
985 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
986 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
987 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
988 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
990 message_put(message);
991 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
995 /* string from parallel call forward (cfp) */
998 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
999 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1000 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1004 vbox_only: /* entry point for answering machine only */
1005 cfu_only: /* entry point for cfu */
1006 cfb_only: /* entry point for cfb */
1007 cfnr_only: /* entry point for cfnr */
1008 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1012 /* only if vbox should be dialed, and terminal is given */
1013 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1014 /* go to the end of p */
1017 /* answering vbox call */
1018 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1020 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1021 FATAL("No memory for VBOX Port instance\n");
1022 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1023 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1026 while(*p!=',' && *p!='\0')
1031 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1032 /* hunt for mISDNport and create Port */
1033 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1035 /* creating EXTERNAL port*/
1036 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1037 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);
1039 FATAL("No memory for Port instance\n");
1040 earlyb = mISDNport->earlyb;
1043 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1044 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1049 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1050 goto check_anycall_intern;
1052 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1053 memset(&dialinginfo, 0, sizeof(dialinginfo));
1054 SCPY(dialinginfo.id, cfp);
1055 dialinginfo.itype = INFO_ITYPE_ISDN;
1056 dialinginfo.ntype = e_dialinginfo.ntype;
1057 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1059 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1061 goto check_anycall_intern;
1063 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1064 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1065 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1066 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1067 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1068 /* if clip is hidden */
1069 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1070 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1071 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1072 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1073 message->param.setup.callerinfo.present = e_ext.callerid_present;
1074 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1076 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1077 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1078 //terminal if (e_dialinginfo.id)
1079 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1080 /* handle restricted caller ids */
1081 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);
1082 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);
1083 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);
1084 /* display callerid if desired for extension */
1085 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));
1086 message_put(message);
1087 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1091 check_anycall_intern:
1092 /* now we have all ports created */
1094 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1096 if (!ea_endpoint->ep_join_id)
1098 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1099 return; /* must exit here */
1103 /* *********************** external call */
1105 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id);
1106 /* call to extenal interfaces */
1107 p = e_dialinginfo.id;
1110 while(*p!=',' && *p!='\0')
1111 SCCAT(number, *p++);
1115 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");
1116 /* hunt for mISDNport and create Port */
1117 /* hunt for mISDNport and create Port */
1118 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1120 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1121 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1123 goto check_anycall_extern;
1125 /* creating EXTERNAL port*/
1126 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1127 if (!mISDNport->gsm)
1128 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);
1131 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1136 FATAL("No memory for Port instance\n");
1137 earlyb = mISDNport->earlyb;
1138 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1139 memset(&dialinginfo, 0, sizeof(dialinginfo));
1140 SCPY(dialinginfo.id, number);
1141 dialinginfo.itype = INFO_ITYPE_ISDN;
1142 dialinginfo.ntype = e_dialinginfo.ntype;
1143 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1145 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1147 goto check_anycall_extern;
1149 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1150 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1151 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1152 SCPY(message->param.setup.dialinginfo.id, number);
1153 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1154 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1155 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1156 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1157 //terminal if (e_dialinginfo.id)
1158 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1159 /* handle restricted caller ids */
1160 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);
1161 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);
1162 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);
1163 /* display callerid if desired for extension */
1164 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));
1165 message_put(message);
1166 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1170 check_anycall_extern:
1171 /* now we have all ports created */
1173 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1175 if (!ea_endpoint->ep_join_id)
1177 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1178 return; /* must exit here */
1186 /* handler for endpoint
1190 int EndpointAppPBX::handler(void)
1192 if (e_crypt_state!=CM_ST_NULL) {
1196 /* process answering machine (play) handling */
1198 if (e_action->index == ACTION_VBOX_PLAY)
1201 /* process action timeout */
1202 if (e_action_timeout)
1203 if (now_d >= e_action_timeout) {
1204 if (e_state!=EPOINT_STATE_CONNECT) {
1206 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea_endpoint->ep_serial);
1207 e_multipoint_cause = 0;
1208 e_multipoint_location = 0;
1209 new_state(EPOINT_STATE_IN_OVERLAP);
1212 return(1); /* we must exit, because our endpoint might be gone */
1214 e_action_timeout = 0;
1217 /* process action timeout */
1218 if (e_match_timeout)
1219 if (now_d >= e_match_timeout) {
1221 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea_endpoint->ep_serial);
1223 return(1); /* we must exit, because our endpoint might be gone */
1228 /* process redialing (epoint redials to port) */
1230 if (now_d >= e_redial) {
1232 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea_endpoint->ep_serial);
1234 new_state(EPOINT_STATE_OUT_SETUP);
1235 /* call special setup routine */
1242 /* process powerdialing (epoint redials to epoint) */
1243 if (e_powerdialing > 0) {
1244 if (now_d >= e_powerdialing) {
1245 e_powerdialing = -1; /* leave power dialing on */
1246 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea_endpoint->ep_serial);
1249 e_ruleset = ruleset_main;
1251 e_rule = e_ruleset->rule_first;
1253 new_state(EPOINT_STATE_IN_OVERLAP);
1259 /* process call forward no response */
1260 if (e_cfnr_release) {
1261 struct port_list *portlist;
1262 struct lcr_msg *message;
1264 if (now >= e_cfnr_release) {
1265 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea_endpoint->ep_serial);
1268 /* release all ports */
1269 while((portlist = ea_endpoint->ep_portlist)) {
1270 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1271 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1272 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1273 message_put(message);
1274 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1275 ea_endpoint->free_portlist(portlist);
1278 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1279 message->param.audiopath = 0;
1280 message_put(message);
1281 /* indicate no patterns */
1282 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1283 message_put(message);
1284 /* set setup state, since we have no response from the new join */
1285 new_state(EPOINT_STATE_OUT_SETUP);
1289 if (now >= e_cfnr_call) {
1290 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea_endpoint->ep_serial, e_ext.cfnr);
1296 /* handle connection to user */
1297 if (e_state == EPOINT_STATE_IDLE) {
1298 /* epoint is idle, check callback */
1300 if (now_d >= e_callback) {
1301 e_callback = 0; /* done with callback */
1302 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea_endpoint->ep_serial);
1303 new_state(EPOINT_STATE_OUT_SETUP);
1309 /* check for password timeout */
1311 if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE) {
1312 struct port_list *portlist;
1314 if (now >= e_password_timeout) {
1315 e_ruleset = ruleset_main;
1317 e_rule = e_ruleset->rule_first;
1319 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea_endpoint->ep_serial, e_extdialing);
1320 trace_header("PASSWORD timeout", DIRECTION_NONE);
1322 e_connectedmode = 0;
1324 new_state(EPOINT_STATE_OUT_DISCONNECT);
1325 portlist = ea_endpoint->ep_portlist;
1327 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1328 set_tone(portlist, "cause_10");
1338 /* doing a hookflash */
1339 void EndpointAppPBX::hookflash(void)
1343 /* be sure that we are active */
1345 e_tx_state = NOTIFY_STATE_ACTIVE;
1347 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1349 if (ea_endpoint->ep_use > 1) {
1350 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1353 /* dialtone after pressing the hash key */
1354 process_hangup(e_join_cause, e_join_location);
1355 e_multipoint_cause = 0;
1356 e_multipoint_location = 0;
1357 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1359 port->set_echotest(0);
1361 if (ea_endpoint->ep_join_id) {
1362 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1364 e_ruleset = ruleset_main;
1366 e_rule = e_ruleset->rule_first;
1368 new_state(EPOINT_STATE_IN_OVERLAP);
1369 e_connectedmode = 1;
1370 SCPY(e_dialinginfo.id, e_ext.prefix);
1371 e_extdialing = e_dialinginfo.id;
1373 if (e_dialinginfo.id[0]) {
1374 set_tone(ea_endpoint->ep_portlist, "dialing");
1377 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1384 /* messages from port
1386 /* port MESSAGE_SETUP */
1387 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1389 struct lcr_msg *message;
1391 int writeext; /* flags need to write extension after modification */
1393 struct interface *interface;
1395 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1397 portlist->port_type = param->setup.port_type;
1398 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1399 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1400 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1401 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1402 // e_dtmf = param->setup.dtmf;
1403 /* screen incoming caller id */
1404 interface = interface_first;
1406 if (!strcmp(e_callerinfo.interface, interface->name)) {
1409 interface = interface->next;
1412 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1413 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1416 /* process extension */
1417 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1418 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1419 /* port makes call from extension */
1420 SCPY(e_callerinfo.extension, e_callerinfo.id);
1421 SCPY(e_ext.number, e_callerinfo.extension);
1422 SCPY(e_extension_interface, e_callerinfo.interface);
1424 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1427 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1428 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1430 /* get extension's info about caller */
1431 if (!read_extension(&e_ext, e_ext.number)) {
1432 /* extension doesn't exist */
1433 trace_header("EXTENSION (not created)", DIRECTION_IN);
1434 add_trace("extension", NULL, "%s", e_ext.number);
1436 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1437 new_state(EPOINT_STATE_OUT_DISCONNECT);
1438 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1439 e_ext.number[0] = '\0'; /* no terminal */
1444 /* put prefix (next) in front of e_dialinginfo.id */
1445 if (e_ext.next[0]) {
1446 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1447 SCPY(e_dialinginfo.id, buffer);
1448 e_ext.next[0] = '\0';
1450 } else if (e_ext.prefix[0]) {
1451 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1452 SCPY(e_dialinginfo.id, buffer);
1455 /* screen caller id by extension's config */
1456 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1458 SCPY(e_callerinfo.name, e_ext.name);
1459 /* use caller id (or if exist: id_next_call) for this call */
1460 if (e_ext.id_next_call_present >= 0) {
1461 SCPY(e_callerinfo.id, e_ext.id_next_call);
1462 /* if we restrict the pesentation */
1463 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1464 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1465 else e_callerinfo.present = e_ext.id_next_call_present;
1466 e_callerinfo.ntype = e_ext.id_next_call_type;
1467 e_ext.id_next_call_present = -1;
1470 SCPY(e_callerinfo.id, e_ext.callerid);
1471 /* if we restrict the pesentation */
1472 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1473 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1474 else e_callerinfo.present = e_ext.callerid_present;
1475 e_callerinfo.ntype = e_ext.callerid_type;
1477 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1479 /* extension is written */
1481 write_extension(&e_ext, e_ext.number);
1483 /* set volume of rx and tx */
1484 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1485 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1486 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1487 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1488 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1489 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1490 message_put(message);
1493 /* start recording if enabled */
1494 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1495 /* check if we are a terminal */
1496 if (e_ext.number[0] == '\0')
1497 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1499 port = find_port_id(portlist->port_id);
1501 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1505 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1506 /* no terminal identification */
1507 e_ext.number[0] = '\0';
1508 e_extension_interface[0] = '\0';
1509 memset(&e_ext, 0, sizeof(e_ext));
1510 e_ext.rights = 4; /* right to dial internat */
1514 e_ruleset = ruleset_main;
1516 e_rule = e_ruleset->rule_first;
1518 e_extdialing = e_dialinginfo.id;
1519 new_state(EPOINT_STATE_IN_SETUP);
1520 if (e_dialinginfo.id[0]) {
1521 set_tone(portlist, "dialing");
1523 if (e_ext.number[0])
1524 set_tone(portlist, "dialpbx");
1526 set_tone(portlist, "dialtone");
1529 if (e_state == EPOINT_STATE_IN_SETUP) {
1530 /* request MORE info, if not already at higher state */
1531 new_state(EPOINT_STATE_IN_OVERLAP);
1532 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1533 message_put(message);
1534 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1538 /* port MESSAGE_INFORMATION */
1539 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1541 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1543 /* ignore information message without digit information */
1544 if (!param->information.id[0])
1549 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1551 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1556 /* if vbox_play is done, the information are just used as they come */
1558 if (e_action->index == ACTION_VBOX_PLAY) {
1559 /* concat dialing string */
1560 SCAT(e_dialinginfo.id, param->information.id);
1565 /* keypad when disconnect but in connected mode */
1566 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1567 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1568 /* processing keypad function */
1569 if (param->information.id[0] == '0') {
1575 /* keypad when connected */
1576 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1577 if (e_ext.keypad || e_enablekeypad) {
1578 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1579 /* processing keypad function */
1580 if (param->information.id[0] == '0') {
1583 if (param->information.id[0])
1584 keypad_function(param->information.id[0]);
1586 if (e_ext.number[0])
1587 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1589 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1594 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1595 if (e_ext.number[0])
1596 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1598 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1602 if (!param->information.id[0])
1604 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1605 set_tone(portlist, "dialing");
1608 if (e_action->index==ACTION_OUTDIAL
1609 || e_action->index==ACTION_EXTERNAL
1610 || e_action->index==ACTION_REMOTE) {
1612 set_tone(portlist, "dialing");
1613 else if (!e_extdialing[0])
1614 set_tone(portlist, "dialing");
1616 /* concat dialing string */
1617 SCAT(e_dialinginfo.id, param->information.id);
1621 /* port MESSAGE_DTMF */
1622 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1624 /* only if dtmf detection is enabled */
1626 trace_header("DTMF (disabled)", DIRECTION_IN);
1630 trace_header("DTMF", DIRECTION_IN);
1631 add_trace("digit", NULL, "%c", param->dtmf);
1635 NOTE: vbox is now handled due to overlap state
1636 /* if vbox_play is done, the dtmf digits are just used as they come */
1638 if (e_action->index == ACTION_VBOX_PLAY) {
1639 /* concat dialing string */
1640 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1641 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1642 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1645 /* continue to process *X# sequences */
1649 /* check for *X# sequence */
1650 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1651 if (e_dtmf_time+3 < now) {
1652 /* the last digit was too far in the past to be a sequence */
1653 if (param->dtmf == '*')
1654 /* only start is allowed in the sequence */
1659 /* we have a sequence of digits, see what we got */
1660 if (param->dtmf == '*')
1662 else if (param->dtmf>='0' && param->dtmf<='9') {
1663 /* we need to have a star before we receive the digit of the sequence */
1664 if (e_dtmf_last == '*')
1665 e_dtmf_last = param->dtmf;
1666 } else if (param->dtmf == '#') {
1668 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1669 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1670 if (e_dtmf_last == '0') {
1674 /* processing keypad function */
1676 keypad_function(e_dtmf_last);
1682 /* set last time of dtmf */
1687 /* check for ## hookflash during dialing */
1689 if (e_action->index==ACTION_PASSWORD
1690 || e_action->index==ACTION_PASSWORD_WRITE)
1692 if (param->dtmf=='#') { /* current digit is '#' */
1693 if (e_state==EPOINT_STATE_IN_DISCONNECT
1694 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1708 /* dialing using dtmf digit */
1709 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1710 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1711 set_tone(portlist, "dialing");
1713 /* concat dialing string */
1714 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1715 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1716 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1722 /* port MESSAGE_CRYPT */
1723 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1725 /* send crypt response to cryptman */
1726 if (param->crypt.type == CR_MESSAGE_IND)
1727 cryptman_msg2man(param->crypt.data, param->crypt.len);
1729 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1732 /* port MESSAGE_OVERLAP */
1733 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1735 struct lcr_msg *message;
1737 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1739 /* signal to call tool */
1740 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1742 if (e_dialing_queue[0] && portlist) {
1743 /* send what we have not dialed yet, because we had no setup complete */
1744 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1745 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1746 SCPY(message->param.information.id, e_dialing_queue);
1747 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1748 message_put(message);
1749 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1750 e_dialing_queue[0] = '\0';
1752 /* check if pattern is available */
1753 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1754 /* indicate patterns */
1755 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1756 message_put(message);
1758 /* connect audio, if not already */
1759 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1760 message->param.audiopath = 1;
1761 message_put(message);
1763 /* indicate no patterns */
1764 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1765 message_put(message);
1767 /* disconnect audio, if not already */
1768 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1769 message->param.audiopath = 0;
1770 message_put(message);
1772 new_state(EPOINT_STATE_OUT_OVERLAP);
1773 /* if we are in a join */
1774 if (ea_endpoint->ep_join_id) {
1775 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1776 memcpy(&message->param, param, sizeof(union parameter));
1777 message_put(message);
1781 /* port MESSAGE_PROCEEDING */
1782 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1784 struct lcr_msg *message;
1786 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1788 /* signal to call tool */
1789 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1791 e_state = EPOINT_STATE_OUT_PROCEEDING;
1792 /* check if pattern is availatle */
1793 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1794 /* indicate patterns */
1795 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1796 message_put(message);
1798 /* connect audio, if not already */
1799 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1800 message->param.audiopath = 1;
1801 message_put(message);
1803 /* indicate no patterns */
1804 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1805 message_put(message);
1807 /* disconnect audio, if not already */
1808 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1809 message->param.audiopath = 0;
1810 message_put(message);
1812 /* if we are in a call */
1813 if (ea_endpoint->ep_join_id) {
1814 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1815 memcpy(&message->param, param, sizeof(union parameter));
1816 message_put(message);
1820 /* port MESSAGE_ALERTING */
1821 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1823 struct lcr_msg *message;
1825 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1827 /* signal to call tool */
1828 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1831 // set_tone(portlist, "hold");
1833 new_state(EPOINT_STATE_OUT_ALERTING);
1834 /* check if pattern is available */
1835 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1836 /* indicate patterns */
1837 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1838 message_put(message);
1840 /* connect audio, if not already */
1841 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1842 message->param.audiopath = 1;
1843 message_put(message);
1845 /* indicate no patterns */
1846 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1847 message_put(message);
1849 /* disconnect audio, if not already */
1850 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1851 message->param.audiopath = 0;
1852 message_put(message);
1854 /* if we are in a call */
1855 if (ea_endpoint->ep_join_id) {
1856 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1857 memcpy(&message->param, param, sizeof(union parameter));
1858 message_put(message);
1862 /* port MESSAGE_CONNECT */
1863 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1865 struct lcr_msg *message;
1867 unsigned int port_id = portlist->port_id;
1868 struct port_list *tportlist;
1870 struct interface *interface;
1872 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1874 /* signal to call tool */
1875 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1877 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1878 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1879 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1880 tportlist = ea_endpoint->ep_portlist;
1881 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1882 tportlist = tportlist->next;
1883 if (tportlist->port_id == port_id)
1884 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1885 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1886 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1887 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1888 message_put(message);
1889 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1890 ea_endpoint->free_portlist(tportlist);
1892 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1896 /* screen incoming connected id */
1897 interface = interface_first;
1899 if (!strcmp(e_connectinfo.interface, interface->name)) {
1902 interface = interface->next;
1905 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1907 /* screen connected name */
1909 SCPY(e_connectinfo.name, e_ext.name);
1911 /* add internal id to colp */
1912 SCPY(e_connectinfo.extension, e_ext.number);
1914 /* we store the connected port number */
1915 SCPY(e_extension_interface, e_connectinfo.interface);
1917 /* for internal and am calls, we get the extension's id */
1918 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1919 SCPY(e_connectinfo.id, e_ext.callerid);
1920 SCPY(e_connectinfo.extension, e_ext.number);
1921 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1922 e_connectinfo.ntype = e_ext.callerid_type;
1923 e_connectinfo.present = e_ext.callerid_present;
1925 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
1926 e_connectinfo.itype = INFO_ITYPE_VBOX;
1927 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
1930 new_state(EPOINT_STATE_CONNECT);
1932 /* set volume of rx and tx */
1933 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1934 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1935 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1936 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1937 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1938 message_put(message);
1941 e_cfnr_call = e_cfnr_release = 0;
1942 if (e_ext.number[0])
1943 e_dtmf = 1; /* allow dtmf */
1946 /* other calls with no caller id (or not available for the extension) and force colp */
1947 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
1948 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
1949 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 */
1950 port = find_port_id(portlist->port_id);
1952 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
1953 e_connectinfo.present = INFO_PRESENT_ALLOWED;
1958 /* send connect to join */
1959 if (ea_endpoint->ep_join_id) {
1960 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1961 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
1962 message_put(message);
1964 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1965 message->param.audiopath = 1;
1966 message_put(message);
1967 } else if (!e_adminid) {
1969 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
1970 SCPY(e_ext.number, e_cbcaller);
1971 new_state(EPOINT_STATE_IN_OVERLAP);
1972 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1974 /* get extension's info about terminal */
1975 if (!read_extension(&e_ext, e_ext.number)) {
1976 /* extension doesn't exist */
1977 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1978 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1979 new_state(EPOINT_STATE_OUT_DISCONNECT);
1980 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1984 /* put prefix in front of e_cbdialing */
1985 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
1986 SCPY(e_dialinginfo.id, buffer);
1987 e_dialinginfo.itype = INFO_ITYPE_ISDN;
1988 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1990 /* use caller id (or if exist: id_next_call) for this call */
1991 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1992 SCPY(e_callerinfo.extension, e_ext.number);
1993 if (e_ext.id_next_call_present >= 0) {
1994 SCPY(e_callerinfo.id, e_ext.id_next_call);
1995 e_callerinfo.present = e_ext.id_next_call_present;
1996 e_callerinfo.ntype = e_ext.id_next_call_type;
1997 e_ext.id_next_call_present = -1;
1998 /* extension is written */
1999 write_extension(&e_ext, e_ext.number);
2001 SCPY(e_callerinfo.id, e_ext.callerid);
2002 e_callerinfo.present = e_ext.callerid_present;
2003 e_callerinfo.ntype = e_ext.callerid_type;
2005 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2007 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2010 /* check if caller id is NOT authenticated */
2011 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2012 /* make call state to enter password */
2013 new_state(EPOINT_STATE_IN_OVERLAP);
2014 e_action = &action_password_write;
2015 e_match_timeout = 0;
2016 e_match_to_action = NULL;
2017 e_dialinginfo.id[0] = '\0';
2018 e_extdialing = strchr(e_dialinginfo.id, '\0');
2019 e_password_timeout = now+20;
2022 /* incoming call (callback) */
2023 e_ruleset = ruleset_main;
2025 e_rule = e_ruleset->rule_first;
2027 e_extdialing = e_dialinginfo.id;
2028 if (e_dialinginfo.id[0]) {
2029 set_tone(portlist, "dialing");
2032 set_tone(portlist, "dialpbx");
2035 } else { /* testcall */
2036 set_tone(portlist, "hold");
2039 /* start recording if enabled, not when answering machine answers */
2040 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)) {
2041 /* check if we are a terminal */
2042 if (e_ext.number[0] == '\0')
2043 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2045 port = find_port_id(portlist->port_id);
2047 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2052 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2053 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2055 struct lcr_msg *message;
2057 unsigned int port_id = portlist->port_id;
2061 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2063 /* signal to call tool */
2064 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2066 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2067 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2068 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2073 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);
2074 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2075 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2077 /* check if we have more than one portlist relation and we just ignore the disconnect */
2078 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2079 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2080 portlist = ea_endpoint->ep_portlist;
2082 if (portlist->port_id == port_id)
2084 portlist = portlist->next;
2087 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2088 if (message_type != MESSAGE_RELEASE) {
2089 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2090 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2091 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2092 message_put(message);
2093 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2095 ea_endpoint->free_portlist(portlist);
2096 return; /* one relation removed */
2098 if (e_state == EPOINT_STATE_CONNECT) {
2099 /* use cause from port after connect */
2100 cause = param->disconnectinfo.cause;
2101 location = param->disconnectinfo.location;
2103 /* use multipoint cause if no connect yet */
2104 if (e_multipoint_cause) {
2105 cause = e_multipoint_cause;
2106 location = e_multipoint_location;
2108 cause = CAUSE_NOUSER;
2109 location = LOCATION_PRIVATE_LOCAL;
2113 e_cfnr_call = e_cfnr_release = 0;
2115 /* process hangup */
2116 process_hangup(e_join_cause, e_join_location);
2117 e_multipoint_cause = 0;
2118 e_multipoint_location = 0;
2120 if (message_type == MESSAGE_DISCONNECT) {
2121 /* tone to disconnected end */
2122 SPRINT(buffer, "cause_%02x", cause);
2123 if (ea_endpoint->ep_portlist)
2124 set_tone(ea_endpoint->ep_portlist, buffer);
2126 new_state(EPOINT_STATE_IN_DISCONNECT);
2129 if (ea_endpoint->ep_join_id) {
2130 int haspatterns = 0;
2131 /* check if pattern is available */
2132 if (ea_endpoint->ep_portlist)
2133 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2134 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
2135 && message_type != MESSAGE_RELEASE) // if we release, we are done
2138 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2139 /* indicate patterns */
2140 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2141 message_put(message);
2142 /* connect audio, if not already */
2143 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2144 message->param.audiopath = 1;
2145 message_put(message);
2146 /* send disconnect */
2147 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2148 memcpy(&message->param, param, sizeof(union parameter));
2149 message_put(message);
2150 /* disable encryption if disconnected */
2151 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2153 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2156 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2159 if (message_type == MESSAGE_RELEASE)
2160 ea_endpoint->free_portlist(portlist);
2161 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */
2162 return; /* must exit here */
2165 /* port MESSAGE_TIMEOUT */
2166 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2170 trace_header("TIMEOUT", DIRECTION_IN);
2171 message_type = MESSAGE_DISCONNECT;
2172 switch (param->state) {
2173 case PORT_STATE_OUT_SETUP:
2174 case PORT_STATE_OUT_OVERLAP:
2175 add_trace("state", NULL, "outgoing setup/dialing");
2177 /* no user responding */
2178 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2179 return; /* must exit here */
2181 case PORT_STATE_IN_SETUP:
2182 case PORT_STATE_IN_OVERLAP:
2183 add_trace("state", NULL, "incoming setup/dialing");
2184 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2185 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2188 case PORT_STATE_OUT_PROCEEDING:
2189 add_trace("state", NULL, "outgoing proceeding");
2191 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2192 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2193 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2194 return; /* must exit here */
2196 case PORT_STATE_IN_PROCEEDING:
2197 add_trace("state", NULL, "incoming proceeding");
2198 param->disconnectinfo.cause = CAUSE_NOUSER;
2199 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2202 case PORT_STATE_OUT_ALERTING:
2203 add_trace("state", NULL, "outgoing alerting");
2205 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2206 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2207 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2208 return; /* must exit here */
2210 case PORT_STATE_CONNECT:
2211 add_trace("state", NULL, "connect");
2213 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2214 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2215 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2216 return; /* must exit here */
2218 case PORT_STATE_IN_ALERTING:
2219 add_trace("state", NULL, "incoming alerting");
2220 param->disconnectinfo.cause = CAUSE_NOANSWER;
2221 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2224 case PORT_STATE_IN_DISCONNECT:
2225 case PORT_STATE_OUT_DISCONNECT:
2226 add_trace("state", NULL, "disconnect");
2228 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2229 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2230 return; /* must exit here */
2233 param->disconnectinfo.cause = 31; /* normal unspecified */
2234 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2237 /* release call, disconnect isdn */
2239 new_state(EPOINT_STATE_OUT_DISCONNECT);
2240 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2241 SCPY(e_tone, cause);
2243 set_tone(portlist, cause);
2244 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2245 portlist = portlist->next;
2247 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2250 /* port MESSAGE_NOTIFY */
2251 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2253 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2255 struct lcr_msg *message;
2256 const char *logtext = "";
2259 /* signal to call tool */
2260 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);
2261 if (param->notifyinfo.notify) {
2262 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2265 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2266 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2267 case INFO_NOTIFY_REMOTE_HOLD:
2268 case INFO_NOTIFY_USER_SUSPENDED:
2269 /* tell call about it */
2270 if (ea_endpoint->ep_join_id) {
2271 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2272 message->param.audiopath = 0;
2273 message_put(message);
2277 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2278 case INFO_NOTIFY_USER_RESUMED:
2279 /* set volume of rx and tx */
2280 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2281 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2283 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2284 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2285 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2286 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2287 message_put(message);
2289 /* set current tone */
2291 set_tone(portlist, e_tone);
2292 /* tell call about it */
2293 if (ea_endpoint->ep_join_id) {
2294 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2295 message->param.audiopath = 1;
2296 message_put(message);
2301 /* get name of notify */
2302 switch(param->notifyinfo.notify) {
2307 logtext = "USER_SUSPENDED";
2310 logtext = "BEARER_SERVICE_CHANGED";
2313 logtext = "USER_RESUMED";
2316 logtext = "CONFERENCE_ESTABLISHED";
2319 logtext = "CONFERENCE_DISCONNECTED";
2322 logtext = "OTHER_PARTY_ADDED";
2325 logtext = "ISOLATED";
2328 logtext = "REATTACHED";
2331 logtext = "OTHER_PARTY_ISOLATED";
2334 logtext = "OTHER_PARTY_REATTACHED";
2337 logtext = "OTHER_PARTY_SPLIT";
2340 logtext = "OTHER_PARTY_DISCONNECTED";
2343 logtext = "CONFERENCE_FLOATING";
2346 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2349 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2352 logtext = "CALL_IS_A_WAITING_CALL";
2355 logtext = "DIVERSION_ACTIVATED";
2358 logtext = "RESERVED_CT_1";
2361 logtext = "RESERVED_CT_2";
2364 logtext = "REVERSE_CHARGING";
2367 logtext = "REMOTE_HOLD";
2370 logtext = "REMOTE_RETRIEVAL";
2373 logtext = "CALL_IS_DIVERTING";
2376 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2381 /* notify call if available */
2382 if (ea_endpoint->ep_join_id) {
2383 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2384 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2385 message_put(message);
2390 /* port MESSAGE_FACILITY */
2391 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2393 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2395 struct lcr_msg *message;
2397 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2398 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2399 message_put(message);
2402 /* port MESSAGE_SUSPEND */
2403 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2404 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2406 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2408 /* epoint is now parked */
2409 ea_endpoint->ep_park = 1;
2410 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2411 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2413 /* remove port relation */
2414 ea_endpoint->free_portlist(portlist);
2417 /* port MESSAGE_RESUME */
2418 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2419 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2421 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2423 /* epoint is now resumed */
2424 ea_endpoint->ep_park = 0;
2429 /* port sends message to the endpoint
2431 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2433 struct port_list *portlist;
2435 portlist = ea_endpoint->ep_portlist;
2437 if (port_id == portlist->port_id)
2439 portlist = portlist->next;
2442 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);
2446 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2447 switch(message_type) {
2448 case MESSAGE_DATA: /* data from port */
2449 /* check if there is a call */
2450 if (!ea_endpoint->ep_join_id)
2452 /* continue if only one portlist */
2453 if (ea_endpoint->ep_portlist->next != NULL)
2455 /* forward message */
2456 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2459 case MESSAGE_TONE_EOF: /* tone is end of file */
2460 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2462 if (e_action->index == ACTION_VBOX_PLAY) {
2465 if (e_action->index == ACTION_EFI) {
2471 case MESSAGE_TONE_COUNTER: /* counter info received */
2472 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);
2474 if (e_action->index == ACTION_VBOX_PLAY) {
2475 e_vbox_counter = param->counter.current;
2476 if (param->counter.max >= 0)
2477 e_vbox_counter_max = param->counter.max;
2481 /* PORT sends SETUP message */
2483 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);
2484 if (e_state!=EPOINT_STATE_IDLE) {
2485 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2488 port_setup(portlist, message_type, param);
2491 /* PORT sends INFORMATION message */
2492 case MESSAGE_INFORMATION: /* additional digits received */
2493 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);
2494 port_information(portlist, message_type, param);
2497 /* PORT sends FACILITY message */
2498 case MESSAGE_FACILITY:
2499 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2500 port_facility(portlist, message_type, param);
2503 /* PORT sends DTMF message */
2504 case MESSAGE_DTMF: /* dtmf digits received */
2505 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);
2506 port_dtmf(portlist, message_type, param);
2509 /* PORT sends CRYPT message */
2510 case MESSAGE_CRYPT: /* crypt response received */
2511 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2512 port_crypt(portlist, message_type, param);
2515 /* PORT sends MORE message */
2516 case MESSAGE_OVERLAP:
2517 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);
2518 if (e_state != EPOINT_STATE_OUT_SETUP) {
2519 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);
2522 port_overlap(portlist, message_type, param);
2525 /* PORT sends PROCEEDING message */
2526 case MESSAGE_PROCEEDING: /* port is proceeding */
2527 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);
2528 if (e_state!=EPOINT_STATE_OUT_SETUP
2529 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2530 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);
2533 port_proceeding(portlist, message_type, param);
2536 /* PORT sends ALERTING message */
2537 case MESSAGE_ALERTING:
2538 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);
2539 if (e_state!=EPOINT_STATE_OUT_SETUP
2540 && e_state!=EPOINT_STATE_OUT_OVERLAP
2541 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2542 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);
2545 port_alerting(portlist, message_type, param);
2548 /* PORT sends CONNECT message */
2549 case MESSAGE_CONNECT:
2550 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);
2551 if (e_state!=EPOINT_STATE_OUT_SETUP
2552 && e_state!=EPOINT_STATE_OUT_OVERLAP
2553 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2554 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2555 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2558 port_connect(portlist, message_type, param);
2561 /* PORT sends DISCONNECT message */
2562 case MESSAGE_DISCONNECT: /* port is disconnected */
2563 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);
2564 port_disconnect_release(portlist, message_type, param);
2567 /* PORT sends a RELEASE message */
2568 case MESSAGE_RELEASE: /* port releases */
2569 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);
2570 /* portlist is release at port_disconnect_release, thanx Paul */
2571 port_disconnect_release(portlist, message_type, param);
2574 /* PORT sends a TIMEOUT message */
2575 case MESSAGE_TIMEOUT:
2576 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);
2577 port_timeout(portlist, message_type, param);
2578 break; /* release */
2580 /* PORT sends a NOTIFY message */
2581 case MESSAGE_NOTIFY:
2582 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);
2583 port_notify(portlist, message_type, param);
2586 /* PORT sends a SUSPEND message */
2587 case MESSAGE_SUSPEND:
2588 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);
2589 port_suspend(portlist, message_type, param);
2590 break; /* suspend */
2592 /* PORT sends a RESUME message */
2593 case MESSAGE_RESUME:
2594 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);
2595 port_resume(portlist, message_type, param);
2599 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2600 /* port assigns bchannel */
2601 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2602 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);
2603 /* only one port is expected to be connected to bchannel */
2604 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2605 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2611 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);
2614 /* Note: this endpoint may be destroyed, so we MUST return */
2618 /* messages from join
2620 /* join MESSAGE_CRYPT */
2621 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2623 switch(param->crypt.type) {
2624 /* message from remote port to "crypt manager" */
2625 case CU_ACTK_REQ: /* activate key-exchange */
2626 case CU_ACTS_REQ: /* activate shared key */
2627 case CU_DACT_REQ: /* deactivate */
2628 case CU_INFO_REQ: /* request last info message */
2629 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2632 /* message from "crypt manager" to user */
2633 case CU_ACTK_CONF: /* key-echange done */
2634 case CU_ACTS_CONF: /* shared key done */
2635 case CU_DACT_CONF: /* deactivated */
2636 case CU_DACT_IND: /* deactivated */
2637 case CU_ERROR_IND: /* receive error message */
2638 case CU_INFO_IND: /* receive info message */
2639 case CU_INFO_CONF: /* receive info message */
2640 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2644 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);
2648 /* join MESSAGE_INFORMATION */
2649 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2651 struct lcr_msg *message;
2656 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2657 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2658 message_put(message);
2659 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2660 portlist = portlist->next;
2664 /* join MESSAGE_FACILITY */
2665 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2667 struct lcr_msg *message;
2669 if (!e_ext.facility && e_ext.number[0]) {
2674 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2675 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2676 message_put(message);
2677 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2678 portlist = portlist->next;
2682 /* join MESSAGE_MORE */
2683 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2685 struct lcr_msg *message;
2687 new_state(EPOINT_STATE_IN_OVERLAP);
2690 if (e_join_pattern && e_ext.own_setup) {
2691 /* disconnect audio */
2692 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2693 message->param.audiopath = 0;
2694 message_put(message);
2696 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2697 if (e_dialinginfo.id[0])
2698 set_tone(portlist, "dialing");
2700 set_tone(portlist, "dialtone");
2703 if (e_dialinginfo.id[0]) {
2704 set_tone(portlist, "dialing");
2706 if (e_ext.number[0])
2707 set_tone(portlist, "dialpbx");
2709 set_tone(portlist, "dialtone");
2713 /* join MESSAGE_PROCEEDING */
2714 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2716 struct lcr_msg *message;
2718 new_state(EPOINT_STATE_IN_PROCEEDING);
2720 /* own proceeding tone */
2721 if (e_join_pattern) {
2722 /* connect / disconnect audio */
2723 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2724 if (e_ext.own_proceeding)
2725 message->param.audiopath = 0;
2727 message->param.audiopath = 1;
2728 message_put(message);
2730 // UCPY(e_join_tone, "proceeding");
2732 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2733 message_put(message);
2734 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2736 set_tone(portlist, "proceeding");
2739 /* join MESSAGE_ALERTING */
2740 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2742 struct lcr_msg *message;
2744 new_state(EPOINT_STATE_IN_ALERTING);
2746 /* own alerting tone */
2747 if (e_join_pattern) {
2748 /* connect / disconnect audio */
2749 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2750 if (e_ext.own_alerting)
2751 message->param.audiopath = 0;
2753 message->param.audiopath = 1;
2754 message_put(message);
2757 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2758 message_put(message);
2759 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2761 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2762 set_tone(portlist, "ringing");
2765 if (e_ext.number[0])
2766 set_tone(portlist, "ringpbx");
2768 set_tone(portlist, "ringing");
2770 if (e_ext.number[0])
2771 e_dtmf = 1; /* allow dtmf */
2774 /* join MESSAGE_CONNECT */
2775 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2777 struct lcr_msg *message;
2779 new_state(EPOINT_STATE_CONNECT);
2780 // UCPY(e_join_tone, "");
2782 if (e_ext.number[0])
2783 e_dtmf = 1; /* allow dtmf */
2786 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2788 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2789 memcpy(&message->param, param, sizeof(union parameter));
2791 /* screen clip if prefix is required */
2792 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2793 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2794 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2795 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2798 /* use internal caller id */
2799 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2800 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2801 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2804 /* handle restricted caller ids */
2805 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);
2806 /* display callerid if desired for extension */
2807 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));
2809 /* use conp, if enabld */
2810 // if (!e_ext.centrex)
2811 // message->param.connectinfo.name[0] = '\0';
2814 message_put(message);
2815 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2817 set_tone(portlist, NULL);
2819 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2820 message->param.audiopath = 1;
2821 message_put(message);
2825 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2826 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2829 struct lcr_msg *message;
2830 struct port_list *portlist = NULL;
2833 /* be sure that we are active */
2835 e_tx_state = NOTIFY_STATE_ACTIVE;
2837 /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
2838 if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2839 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2841 /* set time for power dialing */
2842 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
2845 /* set redial tone */
2846 if (ea_endpoint->ep_portlist) {
2849 set_tone(ea_endpoint->ep_portlist, "redial");
2850 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);
2851 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2852 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2853 new_state(EPOINT_STATE_IN_PROCEEDING);
2854 if (ea_endpoint->ep_portlist) {
2855 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2856 message_put(message);
2857 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2859 /* caused the error, that the first knock sound was not there */
2860 /* set_tone(portlist, "proceeding"); */
2862 /* send display of powerdialing */
2863 if (e_ext.display_dialing) {
2864 portlist = ea_endpoint->ep_portlist;
2866 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2868 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2870 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2871 message_put(message);
2872 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2873 portlist = portlist->next;
2882 if ((e_state!=EPOINT_STATE_CONNECT
2883 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2884 && e_state!=EPOINT_STATE_IN_OVERLAP
2885 && e_state!=EPOINT_STATE_IN_PROCEEDING
2886 && e_state!=EPOINT_STATE_IN_ALERTING)
2887 || !ea_endpoint->ep_portlist) { /* or no port */
2888 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2889 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */
2890 return; /* must exit here */
2893 if (!e_join_cause) {
2894 e_join_cause = param->disconnectinfo.cause;
2895 e_join_location = param->disconnectinfo.location;
2898 /* on release we need the audio again! */
2899 if (message_type == MESSAGE_RELEASE) {
2901 ea_endpoint->ep_join_id = 0;
2903 /* disconnect and select tone */
2904 new_state(EPOINT_STATE_OUT_DISCONNECT);
2905 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2906 /* if own_cause, we must release the join */
2907 if (e_ext.own_cause /* own cause */
2908 || !e_join_pattern) { /* no patterns */
2909 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);
2910 if (message_type != MESSAGE_RELEASE)
2911 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2913 } else { /* else we enable audio */
2914 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2915 message->param.audiopath = 1;
2916 message_put(message);
2918 /* send disconnect message */
2919 SCPY(e_tone, cause);
2920 portlist = ea_endpoint->ep_portlist;
2922 set_tone(portlist, cause);
2923 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2924 portlist = portlist->next;
2928 /* join MESSAGE_SETUP */
2929 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
2931 struct lcr_msg *message;
2932 // struct interface *interface;
2934 /* if we already in setup state, we just update the dialing with new digits */
2935 if (e_state == EPOINT_STATE_OUT_SETUP
2936 || e_state == EPOINT_STATE_OUT_OVERLAP) {
2937 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
2938 /* if digits changed, what we have already dialed */
2939 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
2940 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);
2941 /* release all ports */
2942 while((portlist = ea_endpoint->ep_portlist)) {
2943 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2944 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2945 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2946 message_put(message);
2947 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2948 ea_endpoint->free_portlist(portlist);
2951 /* disconnect audio */
2952 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2953 message->param.audiopath = 0;
2954 message_put(message);
2956 /* get dialing info */
2957 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
2958 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2959 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
2960 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
2961 new_state(EPOINT_STATE_OUT_OVERLAP);
2964 e_redial = now_d + 1; /* set redial one second in the future */
2967 /* if we have a pending redial, so we just adjust the dialing number */
2969 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);
2970 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2973 if (!ea_endpoint->ep_portlist) {
2974 PERROR("ERROR: overlap dialing to a NULL port relation\n");
2976 if (ea_endpoint->ep_portlist->next) {
2977 PERROR("ERROR: overlap dialing to a port_list port relation\n");
2979 if (e_state == EPOINT_STATE_OUT_SETUP) {
2981 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);
2982 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2985 /* get what we have not dialed yet */
2986 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));
2987 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2988 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
2989 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
2990 message_put(message);
2991 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2993 /* always store what we have dialed or queued */
2994 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
2998 if (e_state != EPOINT_STATE_IDLE) {
2999 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3002 /* if an internal extension is dialed, copy that number */
3003 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3004 SCPY(e_ext.number, param->setup.dialinginfo.id);
3005 /* if an internal extension is dialed, get extension's info about caller */
3006 if (e_ext.number[0]) {
3007 if (!read_extension(&e_ext, e_ext.number)) {
3008 e_ext.number[0] = '\0';
3009 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3013 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3014 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3015 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3016 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3018 /* process (voice over) data calls */
3019 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3020 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3021 memset(&e_capainfo, 0, sizeof(e_capainfo));
3022 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3023 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3024 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3027 new_state(EPOINT_STATE_OUT_SETUP);
3028 /* call special setup routine */
3032 /* join MESSAGE_mISDNSIGNAL */
3033 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3035 struct lcr_msg *message;
3038 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3039 memcpy(&message->param, param, sizeof(union parameter));
3040 message_put(message);
3041 portlist = portlist->next;
3045 /* join MESSAGE_NOTIFY */
3046 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3048 struct lcr_msg *message;
3051 if (param->notifyinfo.notify) {
3052 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3053 // /* if notification was generated locally, we turn hold music on/off */
3054 // if (param->notifyinfo.local)
3055 // 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)
3059 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3060 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3062 set_tone(portlist, "");
3063 portlist = portlist->next;
3066 portlist = ea_endpoint->ep_portlist;
3071 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3073 set_tone(portlist, "hold");
3074 portlist = portlist->next;
3076 portlist = ea_endpoint->ep_portlist;
3081 /* save new state */
3082 e_tx_state = new_state;
3085 /* notify port(s) about it */
3087 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3088 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3089 /* handle restricted caller ids */
3090 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3091 /* display callerid if desired for extension */
3092 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));
3093 message_put(message);
3094 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3095 portlist = portlist->next;
3099 /* JOIN sends messages to the endpoint
3101 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3103 struct port_list *portlist;
3104 struct lcr_msg *message;
3107 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3111 portlist = ea_endpoint->ep_portlist;
3113 /* send MESSAGE_DATA to port */
3114 if (message_type == MESSAGE_DATA) {
3115 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3116 /* skip if no port relation */
3119 /* skip if more than one port relation */
3122 /* forward audio data to port */
3123 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3128 // 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);
3129 switch(message_type) {
3130 /* JOIN SENDS TONE message */
3132 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);
3133 set_tone(portlist, param->tone.name);
3136 /* JOIN SENDS CRYPT message */
3138 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);
3139 join_crypt(portlist, message_type, param);
3142 /* JOIN sends INFORMATION message */
3143 case MESSAGE_INFORMATION:
3144 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);
3145 join_information(portlist, message_type, param);
3148 /* JOIN sends FACILITY message */
3149 case MESSAGE_FACILITY:
3150 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);
3151 join_facility(portlist, message_type, param);
3154 /* JOIN sends OVERLAP message */
3155 case MESSAGE_OVERLAP:
3156 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);
3157 if (e_state!=EPOINT_STATE_IN_SETUP
3158 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3159 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3162 join_overlap(portlist, message_type, param);
3165 /* JOIN sends PROCEEDING message */
3166 case MESSAGE_PROCEEDING:
3167 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);
3168 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3169 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3172 join_proceeding(portlist, message_type, param);
3175 /* JOIN sends ALERTING message */
3176 case MESSAGE_ALERTING:
3177 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);
3178 if (e_state!=EPOINT_STATE_IN_OVERLAP
3179 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3180 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3183 join_alerting(portlist, message_type, param);
3186 /* JOIN sends CONNECT message */
3187 case MESSAGE_CONNECT:
3188 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);
3189 if (e_state!=EPOINT_STATE_IN_OVERLAP
3190 && e_state!=EPOINT_STATE_IN_PROCEEDING
3191 && e_state!=EPOINT_STATE_IN_ALERTING) {
3192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3195 join_connect(portlist, message_type, param);
3198 /* JOIN sends DISCONNECT/RELEASE message */
3199 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3200 case MESSAGE_RELEASE: /* JOIN releases */
3201 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);
3202 join_disconnect_release(message_type, param);
3205 /* JOIN sends SETUP message */
3207 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);
3208 join_setup(portlist, message_type, param);
3211 /* JOIN sends special mISDNSIGNAL message */
3212 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3213 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);
3214 join_mISDNsignal(portlist, message_type, param);
3218 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3219 /* JOIN requests bchannel */
3220 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3221 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);
3222 /* only one port is expected to be connected to bchannel */
3229 set_tone(portlist, NULL);
3230 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3231 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3235 /* JOIN has pattern available */
3236 case MESSAGE_PATTERN: /* indicating pattern available */
3237 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);
3238 if (!e_join_pattern) {
3239 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3243 set_tone(portlist, NULL);
3244 portlist = portlist->next;
3246 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3247 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3248 message->param.audiopath = 1;
3249 message_put(message);
3253 /* JOIN has no pattern available */
3254 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3255 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);
3256 if (e_join_pattern) {
3257 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3259 /* disconnect our audio tx and rx */
3260 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3261 message->param.audiopath = 0;
3262 message_put(message);
3267 /* JOIN (dunno at the moment) */
3268 case MESSAGE_REMOTE_AUDIO:
3269 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);
3270 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3271 message->param.audiopath = param->channel;
3272 message_put(message);
3276 /* JOIN sends a notify message */
3277 case MESSAGE_NOTIFY:
3278 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);
3279 join_notify(portlist, message_type, param);
3282 /* JOIN wants keypad / dtmf */
3283 case MESSAGE_ENABLEKEYPAD:
3284 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);
3287 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3292 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);
3297 /* pick_join will connect the first incoming call found. the endpoint
3298 * will receivce a MESSAGE_CONNECT.
3300 int match_list(char *list, char *item)
3302 char *end, *next = NULL;
3304 /* no list make matching */
3309 /* eliminate white spaces */
3310 while (*list <= ' ')
3316 /* if end of list is reached, we return */
3317 if (list[0] == '\0')
3319 /* if we have more than one entry (left) */
3320 if ((end = strchr(list, ',')))
3323 next = end = strchr(list, '\0');
3324 while (*(end-1) <= ' ')
3326 /* if string part matches item */
3327 if (!strncmp(list, item, end-list))
3333 void EndpointAppPBX::pick_join(char *extensions)
3335 struct lcr_msg *message;
3336 struct port_list *portlist;
3338 class EndpointAppPBX *eapp, *found;
3340 class JoinPBX *joinpbx;
3341 struct join_relation *relation;
3344 /* find an endpoint that is ringing internally or vbox with higher priority */
3347 eapp = apppbx_first;
3349 if (eapp!=this && ea_endpoint->ep_portlist) {
3350 portlist = eapp->ea_endpoint->ep_portlist;
3352 if ((port = find_port_id(portlist->port_id))) {
3353 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3354 if (match_list(extensions, eapp->e_ext.number)) {
3360 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3361 && port->p_state==PORT_STATE_OUT_ALERTING)
3362 if (match_list(extensions, eapp->e_ext.number)) {
3366 portlist = portlist->next;
3374 /* if no endpoint found */
3376 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);
3378 set_tone(ea_endpoint->ep_portlist, "cause_10");
3379 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3380 new_state(EPOINT_STATE_OUT_DISCONNECT);
3385 if (ea_endpoint->ep_join_id) {
3386 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3389 if (!eapp->ea_endpoint->ep_join_id) {
3390 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3393 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3395 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3398 if (join->j_type != JOIN_TYPE_PBX) {
3399 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3402 joinpbx = (class JoinPBX *)join;
3403 relation = joinpbx->j_relation;
3405 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3408 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3409 relation = relation->next;
3411 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3416 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3418 if (options.deb & DEBUG_EPOINT) {
3419 class Join *debug_c = join_first;
3420 class Endpoint *debug_e = epoint_first;
3421 class Port *debug_p = port_first;
3423 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3425 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3427 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3428 debug_c = debug_c->next;
3430 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3432 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3433 debug_e = debug_e->next;
3435 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3437 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3438 debug_p = debug_p->next;
3443 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3444 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3445 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3447 /* connnecting our endpoint */
3448 new_state(EPOINT_STATE_CONNECT);
3449 if (e_ext.number[0])
3451 set_tone(ea_endpoint->ep_portlist, NULL);
3453 /* now we send a release to the ringing endpoint */
3454 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3455 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3456 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3457 message_put(message);
3459 /* we send a connect to the join with our caller id */
3460 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3461 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3462 message->param.connectinfo.present = e_callerinfo.present;
3463 message->param.connectinfo.screen = e_callerinfo.screen;
3464 message->param.connectinfo.itype = e_callerinfo.itype;
3465 message->param.connectinfo.ntype = e_callerinfo.ntype;
3466 message_put(message);
3468 /* we send a connect to our port with the remote callerid */
3469 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3470 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3471 message->param.connectinfo.present = eapp->e_callerinfo.present;
3472 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3473 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3474 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3475 /* handle restricted caller ids */
3476 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);
3477 /* display callerid if desired for extension */
3478 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));
3479 message_put(message);
3481 /* we send a connect to the audio path (not for vbox) */
3482 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3483 message->param.audiopath = 1;
3484 message_put(message);
3486 /* beeing paranoid, we make call update */
3487 joinpbx->j_updatebridge = 1;
3489 if (options.deb & DEBUG_EPOINT) {
3490 class Join *debug_c = join_first;
3491 class Endpoint *debug_e = epoint_first;
3492 class Port *debug_p = port_first;
3494 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3496 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3498 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3499 debug_c = debug_c->next;
3501 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3503 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3504 debug_e = debug_e->next;
3506 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3508 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3509 debug_p = debug_p->next;
3515 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3517 void EndpointAppPBX::join_join(void)
3519 struct lcr_msg *message;
3520 struct join_relation *our_relation, *other_relation;
3521 struct join_relation **our_relation_pointer, **other_relation_pointer;
3522 class Join *our_join, *other_join;
3523 class JoinPBX *our_joinpbx, *other_joinpbx;
3524 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3525 class Port *our_port, *other_port;
3526 class Pdss1 *our_pdss1, *other_pdss1;
3528 /* are we a candidate to join a join? */
3529 our_join = find_join_id(ea_endpoint->ep_join_id);
3531 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3534 if (our_join->j_type != JOIN_TYPE_PBX) {
3535 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3538 our_joinpbx = (class JoinPBX *)our_join;
3539 if (!ea_endpoint->ep_portlist) {
3540 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3543 if (!e_ext.number[0]) {
3544 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3547 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3549 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3552 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3553 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3556 our_pdss1 = (class Pdss1 *)our_port;
3558 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3559 other_eapp = apppbx_first;
3561 if (other_eapp == this) {
3562 other_eapp = other_eapp->next;
3565 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);
3566 if (other_eapp->e_ext.number[0] /* has terminal */
3567 && other_eapp->ea_endpoint->ep_portlist /* has port */
3568 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3569 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3570 if (other_port) { /* port still exists */
3571 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3572 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3573 other_pdss1 = (class Pdss1 *)other_port;
3574 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);
3575 if (other_pdss1->p_m_hold /* port is on hold */
3576 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3577 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3580 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3583 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3586 other_eapp = other_eapp->next;
3589 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3592 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3594 /* if we have the same join */
3595 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3596 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3599 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3601 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3604 if (other_join->j_type != JOIN_TYPE_PBX) {
3605 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3608 other_joinpbx = (class JoinPBX *)other_join;
3609 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3610 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3614 /* remove relation to endpoint for join on hold */
3615 other_relation = other_joinpbx->j_relation;
3616 other_relation_pointer = &other_joinpbx->j_relation;
3617 while(other_relation) {
3618 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3619 /* detach other endpoint on hold */
3620 *other_relation_pointer = other_relation->next;
3621 FREE(other_relation, sizeof(struct join_relation));
3623 other_relation = *other_relation_pointer;
3624 other_eapp->ea_endpoint->ep_join_id = 0;
3628 /* change join/hold pointer of endpoint to the new join */
3629 temp_epoint = find_epoint_id(other_relation->epoint_id);
3631 if (temp_epoint->ep_join_id == other_join->j_serial)
3632 temp_epoint->ep_join_id = our_join->j_serial;
3635 other_relation_pointer = &other_relation->next;
3636 other_relation = other_relation->next;
3638 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3640 /* join call relations */
3641 our_relation = our_joinpbx->j_relation;
3642 our_relation_pointer = &our_joinpbx->j_relation;
3643 while(our_relation) {
3644 our_relation_pointer = &our_relation->next;
3645 our_relation = our_relation->next;
3647 *our_relation_pointer = other_joinpbx->j_relation;
3648 other_joinpbx->j_relation = NULL;
3649 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3651 /* release endpoint on hold */
3652 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3653 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3654 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3655 message_put(message);
3657 /* if we are not a partyline, we get partyline state from other join */
3658 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3660 /* remove empty join */
3662 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3664 /* mixer must update */
3665 our_joinpbx->j_updatebridge = 1; /* update mixer flag */
3667 /* we send a retrieve to that endpoint */
3668 // mixer will update the hold-state of the join and send it to the endpoints is changes
3672 /* check if we have an external call
3673 * this is used to check for encryption ability
3675 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3677 struct join_relation *relation;
3679 class JoinPBX *joinpbx;
3680 class Endpoint *epoint;
3682 /* some paranoia check */
3683 if (!ea_endpoint->ep_portlist) {
3684 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3685 *errstr = "No Call";
3688 if (!e_ext.number[0]) {
3689 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3690 *errstr = "No Call";
3694 /* check if we have a join with 2 parties */
3695 join = find_join_id(ea_endpoint->ep_join_id);
3697 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3698 *errstr = "No Call";
3701 if (join->j_type != JOIN_TYPE_PBX) {
3702 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3703 *errstr = "No PBX Call";
3706 joinpbx = (class JoinPBX *)join;
3707 relation = joinpbx->j_relation;
3709 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3710 *errstr = "No Call";
3713 if (!relation->next) {
3714 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3715 *errstr = "No Call";
3718 if (relation->next->next) {
3719 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3720 *errstr = "Err: Conference";
3723 if (relation->epoint_id == ea_endpoint->ep_serial) {
3724 relation = relation->next;
3725 if (relation->epoint_id == ea_endpoint->ep_serial) {
3726 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3727 *errstr = "Software Error";
3732 /* check remote port for external call */
3733 epoint = find_epoint_id(relation->epoint_id);
3735 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3736 *errstr = "No Call";
3739 if (!epoint->ep_portlist) {
3740 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3741 *errstr = "No Call";
3744 *port = find_port_id(epoint->ep_portlist->port_id);
3746 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3747 *errstr = "No Call";
3750 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3751 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3752 *errstr = "No Ext Call";
3755 if ((*port)->p_state != PORT_STATE_CONNECT) {
3756 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3757 *errstr = "No Ext Connect";
3763 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3765 const char *logtext = "unknown";
3768 switch(message_type) {
3770 trace_header("SETUP", dir);
3771 if (dir == DIRECTION_OUT)
3772 add_trace("to", NULL, "CH(%lu)", port_id);
3773 if (dir == DIRECTION_IN)
3774 add_trace("from", NULL, "CH(%lu)", port_id);
3775 if (param->setup.callerinfo.extension[0])
3776 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3777 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3778 switch(param->setup.callerinfo.present) {
3779 case INFO_PRESENT_RESTRICTED:
3780 add_trace("caller id", "present", "restricted");
3782 case INFO_PRESENT_ALLOWED:
3783 add_trace("caller id", "present", "allowed");
3786 add_trace("caller id", "present", "not available");
3788 if (param->setup.callerinfo.ntype2) {
3789 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3790 switch(param->setup.callerinfo.present) {
3791 case INFO_PRESENT_RESTRICTED:
3792 add_trace("caller id2", "present", "restricted");
3794 case INFO_PRESENT_ALLOWED:
3795 add_trace("caller id2", "present", "allowed");
3798 add_trace("caller id2", "present", "not available");
3801 if (param->setup.redirinfo.id[0]) {
3802 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3803 switch(param->setup.redirinfo.present) {
3804 case INFO_PRESENT_RESTRICTED:
3805 add_trace("redir'ing", "present", "restricted");
3807 case INFO_PRESENT_ALLOWED:
3808 add_trace("redir'ing", "present", "allowed");
3811 add_trace("redir'ing", "present", "not available");
3814 if (param->setup.dialinginfo.id[0])
3815 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3816 if (param->setup.dialinginfo.display[0])
3817 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3818 if (param->setup.dialinginfo.sending_complete)
3819 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3823 case MESSAGE_OVERLAP:
3824 trace_header("SETUP ACKNOWLEDGE", dir);
3825 if (dir == DIRECTION_OUT)
3826 add_trace("to", NULL, "CH(%lu)", port_id);
3827 if (dir == DIRECTION_IN)
3828 add_trace("from", NULL, "CH(%lu)", port_id);
3832 case MESSAGE_PROCEEDING:
3833 trace_header("PROCEEDING", dir);
3834 if (dir == DIRECTION_OUT)
3835 add_trace("to", NULL, "CH(%lu)", port_id);
3836 if (dir == DIRECTION_IN)
3837 add_trace("from", NULL, "CH(%lu)", port_id);
3841 case MESSAGE_ALERTING:
3842 trace_header("ALERTING", dir);
3843 if (dir == DIRECTION_OUT)
3844 add_trace("to", NULL, "CH(%lu)", port_id);
3845 if (dir == DIRECTION_IN)
3846 add_trace("from", NULL, "CH(%lu)", port_id);
3850 case MESSAGE_CONNECT:
3851 trace_header("CONNECT", dir);
3852 if (dir == DIRECTION_OUT)
3853 add_trace("to", NULL, "CH(%lu)", port_id);
3854 if (dir == DIRECTION_IN)
3855 add_trace("from", NULL, "CH(%lu)", port_id);
3856 if (param->connectinfo.extension[0])
3857 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3858 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3859 switch(param->connectinfo.present) {
3860 case INFO_PRESENT_RESTRICTED:
3861 add_trace("connect id", "present", "restricted");
3863 case INFO_PRESENT_ALLOWED:
3864 add_trace("connect id", "present", "allowed");
3867 add_trace("connect id", "present", "not available");
3869 if (param->connectinfo.display[0])
3870 add_trace("display", NULL, "%s", param->connectinfo.display);
3874 case MESSAGE_DISCONNECT:
3875 case MESSAGE_RELEASE:
3876 if (message_type == MESSAGE_DISCONNECT)
3877 trace_header("DISCONNECT", dir);
3879 trace_header("RELEASE", dir);
3880 if (dir == DIRECTION_OUT)
3881 add_trace("to", NULL, "CH(%lu)", port_id);
3882 if (dir == DIRECTION_IN)
3883 add_trace("from", NULL, "CH(%lu)", port_id);
3884 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3885 switch(param->disconnectinfo.location) {
3887 add_trace("cause", "location", "0-User");
3889 case LOCATION_PRIVATE_LOCAL:
3890 add_trace("cause", "location", "1-Local-PBX");
3892 case LOCATION_PUBLIC_LOCAL:
3893 add_trace("cause", "location", "2-Local-Exchange");
3895 case LOCATION_TRANSIT:
3896 add_trace("cause", "location", "3-Transit");
3898 case LOCATION_PUBLIC_REMOTE:
3899 add_trace("cause", "location", "4-Remote-Exchange");
3901 case LOCATION_PRIVATE_REMOTE:
3902 add_trace("cause", "location", "5-Remote-PBX");
3904 case LOCATION_INTERNATIONAL:
3905 add_trace("cause", "location", "7-International-Exchange");
3907 case LOCATION_BEYOND:
3908 add_trace("cause", "location", "10-Beyond-Interworking");
3911 add_trace("cause", "location", "%d", param->disconnectinfo.location);
3913 if (param->disconnectinfo.display[0])
3914 add_trace("display", NULL, "%s", param->disconnectinfo.display);
3918 case MESSAGE_NOTIFY:
3919 switch(param->notifyinfo.notify) {
3924 logtext = "USER_SUSPENDED";
3927 logtext = "BEARER_SERVICE_CHANGED";
3930 logtext = "USER_RESUMED";
3933 logtext = "CONFERENCE_ESTABLISHED";
3936 logtext = "CONFERENCE_DISCONNECTED";
3939 logtext = "OTHER_PARTY_ADDED";
3942 logtext = "ISOLATED";
3945 logtext = "REATTACHED";
3948 logtext = "OTHER_PARTY_ISOLATED";
3951 logtext = "OTHER_PARTY_REATTACHED";
3954 logtext = "OTHER_PARTY_SPLIT";
3957 logtext = "OTHER_PARTY_DISCONNECTED";
3960 logtext = "CONFERENCE_FLOATING";
3963 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
3966 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
3969 logtext = "CALL_IS_A_WAITING_CALL";
3972 logtext = "DIVERSION_ACTIVATED";
3975 logtext = "RESERVED_CT_1";
3978 logtext = "RESERVED_CT_2";
3981 logtext = "REVERSE_CHARGING";
3984 logtext = "REMOTE_HOLD";
3987 logtext = "REMOTE_RETRIEVAL";
3990 logtext = "CALL_IS_DIVERTING";
3993 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
3997 trace_header("NOTIFY", dir);
3998 if (dir == DIRECTION_OUT)
3999 add_trace("to", NULL, "CH(%lu)", port_id);
4000 if (dir == DIRECTION_IN)
4001 add_trace("from", NULL, "CH(%lu)", port_id);
4002 if (param->notifyinfo.notify)
4003 add_trace("indicator", NULL, "%s", logtext);
4004 if (param->notifyinfo.id[0]) {
4005 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4006 switch(param->notifyinfo.present) {
4007 case INFO_PRESENT_RESTRICTED:
4008 add_trace("redir'on", "present", "restricted");
4010 case INFO_PRESENT_ALLOWED:
4011 add_trace("redir'on", "present", "allowed");
4014 add_trace("redir'on", "present", "not available");
4017 if (param->notifyinfo.display[0])
4018 add_trace("display", NULL, "%s", param->notifyinfo.display);
4022 case MESSAGE_INFORMATION:
4023 trace_header("INFORMATION", dir);
4024 if (dir == DIRECTION_OUT)
4025 add_trace("to", NULL, "CH(%lu)", port_id);
4026 if (dir == DIRECTION_IN)
4027 add_trace("from", NULL, "CH(%lu)", port_id);
4028 if (param->information.id[0])
4029 add_trace("dialing", NULL, "%s", param->information.id);
4030 if (param->information.display[0])
4031 add_trace("display", NULL, "%s", param->information.display);
4032 if (param->information.sending_complete)
4033 add_trace("complete", NULL, "true", param->information.sending_complete);
4037 case MESSAGE_FACILITY:
4038 trace_header("FACILITY", dir);
4039 if (dir == DIRECTION_OUT)
4040 add_trace("to", NULL, "CH(%lu)", port_id);
4041 if (dir == DIRECTION_IN)
4042 add_trace("from", NULL, "CH(%lu)", port_id);
4047 trace_header("TONE", dir);
4048 if (dir == DIRECTION_OUT)
4049 add_trace("to", NULL, "CH(%lu)", port_id);
4050 if (dir == DIRECTION_IN)
4051 add_trace("from", NULL, "CH(%lu)", port_id);
4052 if (param->tone.name[0]) {
4053 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4054 add_trace("name", NULL, "%s", param->tone.name);
4056 add_trace("off", NULL, NULL);
4060 case MESSAGE_SUSPEND:
4061 case MESSAGE_RESUME:
4062 if (message_type == MESSAGE_SUSPEND)
4063 trace_header("SUSPEND", dir);
4065 trace_header("RESUME", dir);
4066 if (dir == DIRECTION_OUT)
4067 add_trace("to", NULL, "CH(%lu)", port_id);
4068 if (dir == DIRECTION_IN)
4069 add_trace("from", NULL, "CH(%lu)", port_id);
4070 if (param->parkinfo.len)
4071 add_trace("length", NULL, "%d", param->parkinfo.len);
4076 case MESSAGE_BCHANNEL:
4077 trace_header("BCHANNEL", dir);
4078 switch(param->bchannel.type) {
4079 case BCHANNEL_REQUEST:
4080 add_trace("type", NULL, "request");
4082 case BCHANNEL_ASSIGN:
4083 add_trace("type", NULL, "assign");
4085 case BCHANNEL_ASSIGN_ACK:
4086 add_trace("type", NULL, "assign_ack");
4088 case BCHANNEL_REMOVE:
4089 add_trace("type", NULL, "remove");
4091 case BCHANNEL_REMOVE_ACK:
4092 add_trace("type", NULL, "remove_ack");
4095 if (param->bchannel.addr)
4096 add_trace("address", NULL, "%x", param->bchannel.addr);
4102 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4106 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4108 struct lcr_msg *message;
4112 if (!portlist->port_id)
4115 if (!e_connectedmode) {
4116 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4117 message->param.disconnectinfo.cause = cause;
4118 message->param.disconnectinfo.location = location;
4120 SCPY(message->param.disconnectinfo.display, display);
4122 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4124 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4126 SCPY(message->param.notifyinfo.display, display);
4128 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4130 message_put(message);
4131 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);