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));
78 e_password_timeout = 0;
79 e_multipoint_cause = 0;
80 e_multipoint_location = 0;
81 e_dialing_queue[0] = '\0';
83 e_crypt_state = CM_ST_NULL;
84 e_crypt_keyengine_busy = 0;
85 e_crypt_info[0] = '\0';
88 e_tx_state = NOTIFY_STATE_ACTIVE;
89 e_rx_state = NOTIFY_STATE_ACTIVE;
90 e_join_cause = e_join_location = 0;
91 /*********************************
92 *********************************
93 ********* ATTENTION *************
94 *********************************
95 *********************************/
96 /* if you add new values, that must be initialized, also check if they must
97 * be initialized when doing callback
103 * EpointAppPBX destructor
105 EndpointAppPBX::~EndpointAppPBX(void)
107 class EndpointAppPBX *temp, **tempp;
111 tempp = &apppbx_first;
121 FATAL("Endpoint not in endpoint's list.\n");
128 * trace header for application
130 void EndpointAppPBX::trace_header(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)
159 trace_header("NEW STATE", DIRECTION_NONE);
160 add_trace("state", "old", "%s", state_name[e_state]);
161 add_trace("state", "new", "%s", state_name[state]);
169 /* release join and port (as specified)
171 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause)
173 struct port_list *portlist;
174 struct lcr_msg *message;
177 /* message to test call */
178 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
180 /* if a release is pending */
181 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY)
183 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
184 if (ea_endpoint->ep_join_id)
186 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
187 message->param.disconnectinfo.cause = joincause;
188 message->param.disconnectinfo.location = joinlocation;
189 message_put(message);
190 ea_endpoint->ep_join_id = 0;
194 if (release != RELEASE_PORT_JOINONLY)
197 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
202 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY)
204 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
205 while((portlist = ea_endpoint->ep_portlist))
207 if (portlist->port_id)
209 SPRINT(cause, "cause_%02x", portcause);
210 set_tone(portlist, cause);
211 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
212 message->param.disconnectinfo.cause = portcause;
213 message->param.disconnectinfo.location = portlocation;
214 message_put(message);
215 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
217 ea_endpoint->free_portlist(portlist);
220 /* if callback is enabled, call back with the given caller id */
223 /* reset some stuff */
224 new_state(EPOINT_STATE_IDLE);
225 memset(&e_connectinfo, 0, sizeof(struct connect_info));
226 memset(&e_redirinfo, 0, sizeof(struct redir_info));
227 e_start = e_stop = 0;
228 e_ruleset = ruleset_main;
230 e_rule = e_ruleset->rule_first;
232 e_action_timeout = 0;
234 e_match_to_action = NULL;
236 e_extdialing = e_dialinginfo.id;
243 e_multipoint_cause = 0;
244 e_multipoint_location = 0;
245 e_dialing_queue[0] = '\0';
247 e_crypt_state = CM_ST_NULL;
248 e_crypt_keyengine_busy = 0;
249 e_crypt_info[0] = '\0';
253 e_tx_state = NOTIFY_STATE_ACTIVE;
254 e_rx_state = NOTIFY_STATE_ACTIVE;
255 e_join_cause = e_join_location = 0;
257 /* the caller info of the callback user */
258 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
259 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
260 /* create dialing by callerinfo */
261 if (e_ext.number[0] && e_extension_interface[0])
263 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
264 /* create callback to the current terminal */
265 SCPY(e_dialinginfo.id, e_ext.number);
266 SCPY(e_dialinginfo.interfaces, e_extension_interface);
267 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
268 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
273 SCPY(e_dialinginfo.id, e_cbto);
276 /* numberrize caller id and use it to dial to the callback */
277 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
279 e_dialinginfo.itype = INFO_ITYPE_ISDN;
280 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
281 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
286 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
287 ea_endpoint->ep_use--; /* when e_lock is 0, the endpoint will be deleted */
293 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
294 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
296 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");
298 /* caller id is not restricted, so we do nothing */
299 if (*present != INFO_PRESENT_RESTRICTED)
302 /* only extensions are restricted */
306 /* if we enabled anonymouse ignore */
307 if (ext->anon_ignore)
310 /* else we remove the caller id */
314 *ntype = INFO_NTYPE_UNKNOWN;
316 // *screen = INFO_SCREEN_USER;
317 // maybe we should not make voip address anonymous
320 // maybe it's no fraud to present extension id
322 // extension[0] = '\0';
327 /* used display message to display callerid as available */
328 char *EndpointAppPBX::apply_callerid_display(char *id, int itype, int ntype, int present, int screen, char *extension, char *name)
330 static char display[81];
333 char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
335 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");
344 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
346 /* internal extension's caller id */
347 if (extension[0] && e_ext.display_int)
350 SCAT(display, extension);
353 if (itype == INFO_ITYPE_VBOX)
354 SCAT(display, "(vbox)");
356 SCAT(display, "(int)");
359 /* external caller id */
360 if (!extension[0] && e_ext.display_ext)
366 if (present == INFO_PRESENT_RESTRICTED)
367 SCAT(display, "anonymous");
369 SCAT(display, "unknown");
376 /* display if callerid is anonymouse but available due anon-ignore */
377 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED)
380 SCAT(display, "unknown");
383 SCAT(display, " anon");
386 /* display if callerid is anonymouse but available due anon-ignore */
387 if (e_ext.display_fake && screen==INFO_SCREEN_USER && present!=INFO_PRESENT_NULL)
393 if (present == INFO_PRESENT_RESTRICTED)
394 SCAT(display, "anonymous");
396 SCAT(display, "unknown");
401 SCAT(display, " fake");
405 if (name[0] && e_ext.display_name)
407 if (!display[0] && cid[0])
418 * uses the current state to notify activity
420 void EndpointAppPBX::notify_active(void)
422 struct port_list *portlist = ea_endpoint->ep_portlist;
423 struct lcr_msg *message;
428 case NOTIFY_STATE_ACTIVE:
429 /* we are already active, so we don't do anything */
432 case NOTIFY_STATE_SUSPEND:
433 notify = INFO_NOTIFY_USER_RESUMED;
436 set_tone(portlist, NULL);
437 portlist = portlist->next;
439 portlist = ea_endpoint->ep_portlist;
442 case NOTIFY_STATE_HOLD:
443 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
446 set_tone(portlist, NULL);
447 portlist = portlist->next;
449 portlist = ea_endpoint->ep_portlist;
452 case NOTIFY_STATE_CONFERENCE:
453 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
456 set_tone(portlist, NULL);
457 portlist = portlist->next;
459 portlist = ea_endpoint->ep_portlist;
463 PERROR("unknown e_tx_state = %d\n", e_tx_state);
469 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
470 message->param.notifyinfo.notify = notify;
471 message_put(message);
472 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
473 portlist = portlist->next;
479 * keypad functions during call. one example to use this is to put a call on hold or start a conference
481 void EndpointAppPBX::keypad_function(char digit)
484 /* we must be in a call, in order to send messages to the call */
485 if (e_ext.number[0] == '\0')
487 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
493 /* join conference */
495 if (ea_endpoint->ep_join_id == 0)
497 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
500 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
506 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
510 /* crypt key-exchange */
512 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
518 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
523 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
528 /* set tone pattern for port */
529 void EndpointAppPBX::set_tone(struct port_list *portlist, char *tone)
531 struct lcr_msg *message;
536 /* store for suspended processes */
540 if (e_join_pattern /* pattern are provided */
541 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
542 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
543 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
544 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
545 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
546 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
547 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
548 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
549 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
550 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
551 && tone[0] && !!strncmp(tone,"crypt_*",6))
553 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
559 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
560 SCPY(message->param.tone.dir, e_ext.tones_dir[0]?e_ext.tones_dir:options.tones_dir);
561 SCPY(message->param.tone.name, tone);
562 message_put(message);
563 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
566 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
573 * hunts an mISDNport that is available for an outgoing call
574 * if no ifname was given, any interface that is not an extension
577 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
579 struct interface *interface;
580 struct interface_port *ifport, *ifport_start;
581 struct select_channel *selchannel;
582 struct mISDNport *mISDNport;
585 interface = interface_first;
587 /* first find the given interface or, if not given, one with no extension */
592 /* check for given interface */
595 if (!strcasecmp(interface->name, ifname))
597 /* found explicit interface */
598 trace_header("CHANNEL SELECTION (found interface)", DIRECTION_NONE);
599 add_trace("interface", NULL, "%s", ifname);
606 if (!interface->extension)
608 /* found non extension */
609 trace_header("CHANNEL SELECTION (found non extension interface)", DIRECTION_NONE);
610 add_trace("interface", NULL, "%s", interface->name);
616 interface = interface->next;
620 /* see if interface has ports */
621 if (!interface->ifport)
624 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
625 add_trace("interface", NULL, "%s", interface->name);
627 interface = interface->next;
631 /* select port by algorithm */
632 ifport_start = interface->ifport;
634 if (interface->hunt == HUNT_ROUNDROBIN)
636 while(ifport_start->next && index<interface->hunt_next)
638 ifport_start = ifport_start->next;
641 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
642 add_trace("port", NULL, "%d", ifport_start->portnum);
643 add_trace("position", NULL, "%d", index);
648 ifport = ifport_start;
651 /* see if port is available */
652 if (!ifport->mISDNport)
654 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
655 add_trace("port", NULL, "%d", ifport->portnum);
656 add_trace("position", NULL, "%d", index);
660 mISDNport = ifport->mISDNport;
662 /* see if port is administratively blocked */
665 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
666 add_trace("port", NULL, "%d", ifport->portnum);
667 add_trace("position", NULL, "%d", index);
672 /* see if link is up on PTP*/
673 if (mISDNport->l2hold && !mISDNport->l2link)
675 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
676 add_trace("port", NULL, "%d", ifport->portnum);
677 add_trace("position", NULL, "%d", index);
682 /* check for channel form selection list */
684 selchannel = ifport->out_channel;
687 switch(selchannel->channel)
689 case CHANNEL_FREE: /* free channel */
690 if (mISDNport->b_reserved >= mISDNport->b_num)
691 break; /* all channel in use or reserverd */
694 while(i < mISDNport->b_num)
696 if (mISDNport->b_port[i] == NULL)
698 *channel = i+1+(i>=15);
699 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
700 add_trace("port", NULL, "%d", ifport->portnum);
701 add_trace("position", NULL, "%d", index);
702 add_trace("channel", NULL, "%d", *channel);
710 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
711 add_trace("port", NULL, "%d", ifport->portnum);
712 add_trace("position", NULL, "%d", index);
716 case CHANNEL_ANY: /* don't ask for channel */
717 if (mISDNport->b_reserved >= mISDNport->b_num)
719 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
720 add_trace("port", NULL, "%d", ifport->portnum);
721 add_trace("position", NULL, "%d", index);
722 add_trace("total", NULL, "%d", mISDNport->b_num);
723 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
725 break; /* all channel in use or reserverd */
727 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
728 add_trace("port", NULL, "%d", ifport->portnum);
729 add_trace("position", NULL, "%d", index);
731 *channel = CHANNEL_ANY;
734 case CHANNEL_NO: /* call waiting */
735 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
736 add_trace("port", NULL, "%d", ifport->portnum);
737 add_trace("position", NULL, "%d", index);
739 *channel = CHANNEL_NO;
743 if (selchannel->channel<1 || selchannel->channel==16)
745 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
746 add_trace("port", NULL, "%d", ifport->portnum);
747 add_trace("position", NULL, "%d", index);
748 add_trace("channel", NULL, "%d", selchannel->channel);
750 break; /* invalid channels */
752 i = selchannel->channel-1-(selchannel->channel>=17);
753 if (i >= mISDNport->b_num)
755 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
756 add_trace("port", NULL, "%d", ifport->portnum);
757 add_trace("position", NULL, "%d", index);
758 add_trace("channel", NULL, "%d", selchannel->channel);
759 add_trace("channels", NULL, "%d", mISDNport->b_num);
761 break; /* channel not in port */
763 if (mISDNport->b_port[i] == NULL)
765 *channel = selchannel->channel;
766 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
767 add_trace("port", NULL, "%d", ifport->portnum);
768 add_trace("position", NULL, "%d", index);
769 add_trace("channel", NULL, "%d", *channel);
776 break; /* found channel */
777 selchannel = selchannel->next;
780 /* if channel was found, return mISDNport and channel */
783 /* setting next port to start next time */
784 if (interface->hunt == HUNT_ROUNDROBIN)
789 interface->hunt_next = index;
795 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
796 add_trace("port", NULL, "%d", ifport->portnum);
797 add_trace("position", NULL, "%d", index);
801 /* go next port, until all ports are checked */
803 ifport = ifport->next;
807 ifport = interface->ifport;
809 if (ifport != ifport_start)
813 interface = interface->next;
817 return(NULL); /* no port found */
820 /* outgoing setup to port(s)
821 * ports will be created and a setup is sent if everything is ok. otherwhise
822 * the endpoint is destroyed.
824 void EndpointAppPBX::out_setup(void)
826 struct dialing_info dialinginfo;
828 // class pdss1 *pdss1;
829 struct port_list *portlist;
830 struct lcr_msg *message;
832 int cause = CAUSE_RESSOURCEUNAVAIL;
835 struct mISDNport *mISDNport;
838 class EndpointAppPBX *atemp;
839 // char allowed_ports[256];
841 char ifname[sizeof(e_ext.interfaces)],
843 struct port_settings port_settings;
847 /* create settings for creating port */
848 memset(&port_settings, 0, sizeof(port_settings));
850 SCPY(port_settings.tones_dir, e_ext.tones_dir);
852 SCPY(port_settings.tones_dir, options.tones_dir);
853 port_settings.no_seconds = e_ext.no_seconds;
855 /* 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 */
857 /* check what dialinginfo.itype we got */
858 switch(e_dialinginfo.itype)
860 /* *********************** call to extension or vbox */
861 case INFO_ITYPE_ISDN_EXTENSION:
862 /* check if we deny incoming calls when we use an extension */
863 if (e_ext.noknocking)
865 atemp = apppbx_first;
869 if (!strcmp(atemp->e_ext.number, e_ext.number))
875 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
876 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYSPE_ join, port */
877 return; /* must exit here */
880 /* FALL THROUGH !!!! */
881 case INFO_ITYPE_VBOX:
882 /* get dialed extension's info */
883 // SCPY(exten, e_dialinginfo.id);
884 // if (strchr(exten, ','))
885 // *strchr(exten, ',') = '\0';
886 // if (!read_extension(&e_ext, exten))
887 if (!read_extension(&e_ext, e_dialinginfo.id))
889 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
890 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
891 return; /* must exit here */
894 if (e_dialinginfo.itype == INFO_ITYPE_VBOX)
896 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
901 /* string from unconditional call forward (cfu) */
905 /* present to forwarded party */
906 if (e_ext.anon_ignore && e_callerinfo.id[0])
908 e_callerinfo.present = INFO_PRESENT_ALLOWED;
910 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
914 /* string from busy call forward (cfb) */
918 class EndpointAppPBX *checkapp = apppbx_first;
921 if (checkapp != this) /* any other endpoint except our own */
923 if (!strcmp(checkapp->e_ext.number, e_ext.number))
925 /* present to forwarded party */
926 if (e_ext.anon_ignore && e_callerinfo.id[0])
928 e_callerinfo.present = INFO_PRESENT_ALLOWED;
930 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
934 checkapp = checkapp->next;
938 /* string from no-response call forward (cfnr) */
942 /* when cfnr is done, out_setup() will setup the call */
945 /* present to forwarded party */
946 if (e_ext.anon_ignore && e_callerinfo.id[0])
948 e_callerinfo.present = INFO_PRESENT_ALLOWED;
952 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
954 e_cfnr_release = now + e_ext.cfnr_delay;
955 e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */
956 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);
960 /* call to all internal interfaces */
961 p = e_ext.interfaces;
962 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
966 while(*p!=',' && *p!='\0')
971 /* found interface */
972 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
973 /* hunt for mISDNport and create Port */
974 mISDNport = hunt_port(ifname, &channel);
977 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
978 add_trace("interface", NULL, "%s", ifname);
982 /* creating INTERNAL port */
983 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
984 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force);
986 FATAL("No memory for DSS1 Port instance\n");
987 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
988 memset(&dialinginfo, 0, sizeof(dialinginfo));
989 SCPY(dialinginfo.id, e_dialinginfo.id);
990 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
991 dialinginfo.ntype = e_dialinginfo.ntype;
992 /* create port_list relation */
993 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
996 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
998 goto check_anycall_intern;
1000 /* directory.list */
1001 if (e_callerinfo.id[0] && e_ext.display_name)
1003 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1005 SCPY(e_callerinfo.name, dirname);
1007 // dss1 = (class Pdss1 *)port;
1009 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1010 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1011 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1012 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1013 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1014 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1015 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1016 //terminal if (e_dialinginfo.id)
1017 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1018 /* handle restricted caller ids */
1019 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);
1020 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);
1021 /* display callerid if desired for extension */
1022 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));
1023 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1024 /* use cnip, if enabld */
1025 // if (!e_ext.centrex)
1026 // message->param.setup.callerinfo.name[0] = '\0';
1027 /* screen clip if prefix is required */
1028 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0])
1030 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1031 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1032 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1034 /* use internal caller id */
1035 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore))
1037 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1038 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1040 message_put(message);
1041 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1045 /* string from parallel call forward (cfp) */
1049 if (e_ext.anon_ignore && e_callerinfo.id[0])
1051 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1055 vbox_only: /* entry point for answering machine only */
1056 cfu_only: /* entry point for cfu */
1057 cfb_only: /* entry point for cfb */
1058 cfnr_only: /* entry point for cfnr */
1059 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1064 /* only if vbox should be dialed, and terminal is given */
1065 if (!strcmp(p, "vbox") && e_ext.number[0])
1067 /* go to the end of p */
1070 /* answering vbox call */
1071 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1073 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1074 FATAL("No memory for VBOX Port instance\n");
1075 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1076 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1080 while(*p!=',' && *p!='\0')
1085 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1086 /* hunt for mISDNport and create Port */
1087 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1090 /* creating EXTERNAL port*/
1091 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1092 if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force)))
1093 FATAL("No memory for DSS1 Port instance\n");
1094 earlyb = mISDNport->earlyb;
1098 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1099 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1105 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1106 goto check_anycall_intern;
1108 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1109 memset(&dialinginfo, 0, sizeof(dialinginfo));
1110 SCPY(dialinginfo.id, cfp);
1111 dialinginfo.itype = INFO_ITYPE_ISDN;
1112 dialinginfo.ntype = e_dialinginfo.ntype;
1113 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1116 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1118 goto check_anycall_intern;
1120 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1121 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1122 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1123 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1124 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1125 /* if clip is hidden */
1126 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT)
1128 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1129 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1130 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1131 message->param.setup.callerinfo.present = e_ext.callerid_present;
1133 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1134 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1135 //terminal if (e_dialinginfo.id)
1136 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1137 /* handle restricted caller ids */
1138 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);
1139 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);
1140 /* display callerid if desired for extension */
1141 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));
1142 message_put(message);
1143 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1147 check_anycall_intern:
1148 /* now we have all ports created */
1151 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1153 if (!ea_endpoint->ep_join_id)
1155 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1156 return; /* must exit here */
1160 /* *********************** external call */
1162 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id);
1163 /* call to extenal interfaces */
1164 p = e_dialinginfo.id;
1168 while(*p!=',' && *p!='\0')
1169 SCCAT(number, *p++);
1173 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");
1174 /* hunt for mISDNport and create Port */
1175 /* hunt for mISDNport and create Port */
1176 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1179 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1180 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1182 goto check_anycall_extern;
1184 /* creating EXTERNAL port*/
1185 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1186 if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force)))
1187 FATAL("No memory for DSS1 Port instance\n");
1188 earlyb = mISDNport->earlyb;
1189 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1190 memset(&dialinginfo, 0, sizeof(dialinginfo));
1191 SCPY(dialinginfo.id, number);
1192 dialinginfo.itype = INFO_ITYPE_ISDN;
1193 dialinginfo.ntype = e_dialinginfo.ntype;
1194 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1197 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1199 goto check_anycall_extern;
1201 // dss1 = (class Pdss1 *)port;
1202 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1203 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1204 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1205 SCPY(message->param.setup.dialinginfo.id, number);
1206 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1207 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1208 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1209 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1210 //terminal if (e_dialinginfo.id)
1211 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1212 /* handle restricted caller ids */
1213 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);
1214 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);
1215 /* display callerid if desired for extension */
1216 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));
1217 message_put(message);
1218 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1222 check_anycall_extern:
1223 /* now we have all ports created */
1226 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1228 if (!ea_endpoint->ep_join_id)
1230 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1231 return; /* must exit here */
1239 /* handler for endpoint
1243 int EndpointAppPBX::handler(void)
1245 if (e_crypt_state!=CM_ST_NULL)
1250 /* process answering machine (play) handling */
1253 if (e_action->index == ACTION_VBOX_PLAY)
1256 /* process action timeout */
1257 if (e_action_timeout)
1258 if (now_d >= e_action_timeout)
1260 if (e_state!=EPOINT_STATE_CONNECT)
1263 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea_endpoint->ep_serial);
1264 e_multipoint_cause = 0;
1265 e_multipoint_location = 0;
1266 new_state(EPOINT_STATE_IN_OVERLAP);
1269 return(1); /* we must exit, because our endpoint might be gone */
1271 e_action_timeout = 0;
1274 /* process action timeout */
1275 if (e_match_timeout)
1276 if (now_d >= e_match_timeout)
1279 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea_endpoint->ep_serial);
1281 return(1); /* we must exit, because our endpoint might be gone */
1286 /* process redialing (epoint redials to port) */
1289 if (now_d >= e_redial)
1292 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea_endpoint->ep_serial);
1294 new_state(EPOINT_STATE_OUT_SETUP);
1295 /* call special setup routine */
1302 /* process powerdialing (epoint redials to epoint) */
1303 if (e_powerdialing > 0)
1305 if (now_d >= e_powerdialing)
1307 e_powerdialing = -1; /* leave power dialing on */
1308 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea_endpoint->ep_serial);
1311 e_ruleset = ruleset_main;
1313 e_rule = e_ruleset->rule_first;
1315 new_state(EPOINT_STATE_IN_OVERLAP);
1321 /* process call forward no response */
1324 struct port_list *portlist;
1325 struct lcr_msg *message;
1327 if (now >= e_cfnr_release)
1329 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea_endpoint->ep_serial);
1332 /* release all ports */
1333 while((portlist = ea_endpoint->ep_portlist))
1335 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1336 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1337 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1338 message_put(message);
1339 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1340 ea_endpoint->free_portlist(portlist);
1343 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1344 message->param.audiopath = 0;
1345 message_put(message);
1346 /* indicate no patterns */
1347 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1348 message_put(message);
1349 /* set setup state, since we have no response from the new join */
1350 new_state(EPOINT_STATE_OUT_SETUP);
1355 if (now >= e_cfnr_call)
1357 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea_endpoint->ep_serial, e_ext.cfnr);
1363 /* handle connection to user */
1364 if (e_state == EPOINT_STATE_IDLE)
1366 /* epoint is idle, check callback */
1368 if (now_d >= e_callback)
1370 e_callback = 0; /* done with callback */
1371 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea_endpoint->ep_serial);
1372 new_state(EPOINT_STATE_OUT_SETUP);
1378 /* check for password timeout */
1380 if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE)
1382 struct port_list *portlist;
1384 if (now >= e_password_timeout)
1386 e_ruleset = ruleset_main;
1388 e_rule = e_ruleset->rule_first;
1390 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea_endpoint->ep_serial, e_extdialing);
1391 trace_header("PASSWORD timeout", DIRECTION_NONE);
1393 e_connectedmode = 0;
1395 new_state(EPOINT_STATE_OUT_DISCONNECT);
1396 portlist = ea_endpoint->ep_portlist;
1399 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1400 set_tone(portlist, "cause_10");
1410 /* doing a hookflash */
1411 void EndpointAppPBX::hookflash(void)
1415 /* be sure that we are active */
1417 e_tx_state = NOTIFY_STATE_ACTIVE;
1419 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1421 if (ea_endpoint->ep_use > 1)
1423 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1426 /* dialtone after pressing the hash key */
1427 process_hangup(e_join_cause, e_join_location);
1428 e_multipoint_cause = 0;
1429 e_multipoint_location = 0;
1430 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1433 port->set_echotest(0);
1435 if (ea_endpoint->ep_join_id)
1437 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1439 e_ruleset = ruleset_main;
1441 e_rule = e_ruleset->rule_first;
1443 new_state(EPOINT_STATE_IN_OVERLAP);
1444 e_connectedmode = 1;
1445 SCPY(e_dialinginfo.id, e_ext.prefix);
1446 e_extdialing = e_dialinginfo.id;
1448 if (e_dialinginfo.id[0])
1450 set_tone(ea_endpoint->ep_portlist, "dialing");
1454 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1461 /* messages from port
1463 /* port MESSAGE_SETUP */
1464 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1466 struct lcr_msg *message;
1468 int writeext; /* flags need to write extension after modification */
1470 struct interface *interface;
1472 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1474 portlist->port_type = param->setup.port_type;
1475 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1476 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1477 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1478 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1479 e_dtmf = param->setup.dtmf;
1480 /* screen incoming caller id */
1481 interface = interface_first;
1484 if (!strcmp(e_callerinfo.interface, interface->name))
1488 interface = interface->next;
1491 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1493 /* process extension */
1494 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1496 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1497 /* port makes call from extension */
1498 SCPY(e_callerinfo.extension, e_callerinfo.id);
1499 SCPY(e_ext.number, e_callerinfo.extension);
1500 SCPY(e_extension_interface, e_callerinfo.interface);
1503 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1506 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1508 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1510 /* get extension's info about caller */
1511 if (!read_extension(&e_ext, e_ext.number))
1513 /* extension doesn't exist */
1514 trace_header("EXTENSION (not created)", DIRECTION_IN);
1515 add_trace("extension", NULL, "%s", e_ext.number);
1517 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1518 new_state(EPOINT_STATE_OUT_DISCONNECT);
1519 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1520 e_ext.number[0] = '\0'; /* no terminal */
1525 /* put prefix (next) in front of e_dialinginfo.id */
1528 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1529 SCPY(e_dialinginfo.id, buffer);
1530 e_ext.next[0] = '\0';
1532 } else if (e_ext.prefix[0])
1534 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1535 SCPY(e_dialinginfo.id, buffer);
1538 /* screen caller id by extension's config */
1539 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1541 SCPY(e_callerinfo.name, e_ext.name);
1542 /* use caller id (or if exist: id_next_call) for this call */
1543 if (e_ext.id_next_call_present >= 0)
1545 SCPY(e_callerinfo.id, e_ext.id_next_call);
1546 /* if we restrict the pesentation */
1547 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1548 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1549 else e_callerinfo.present = e_ext.id_next_call_present;
1550 e_callerinfo.ntype = e_ext.id_next_call_type;
1551 e_ext.id_next_call_present = -1;
1555 SCPY(e_callerinfo.id, e_ext.callerid);
1556 /* if we restrict the pesentation */
1557 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1558 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1559 else e_callerinfo.present = e_ext.callerid_present;
1560 e_callerinfo.ntype = e_ext.callerid_type;
1563 /* extension is written */
1565 write_extension(&e_ext, e_ext.number);
1567 /* set volume of rx and tx */
1568 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1569 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
1571 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1572 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1573 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1574 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1575 message_put(message);
1578 /* start recording if enabled */
1579 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO))
1581 /* check if we are a terminal */
1582 if (e_ext.number[0] == '\0')
1583 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1586 port = find_port_id(portlist->port_id);
1588 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1593 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1594 /* no terminal identification */
1595 e_ext.number[0] = '\0';
1596 e_extension_interface[0] = '\0';
1597 memset(&e_ext, 0, sizeof(e_ext));
1598 e_ext.rights = 4; /* right to dial internat */
1602 e_ruleset = ruleset_main;
1604 e_rule = e_ruleset->rule_first;
1606 e_extdialing = e_dialinginfo.id;
1607 new_state(EPOINT_STATE_IN_SETUP);
1608 if (e_dialinginfo.id[0])
1610 set_tone(portlist, "dialing");
1613 if (e_ext.number[0])
1614 set_tone(portlist, "dialpbx");
1616 set_tone(portlist, "dialtone");
1619 if (e_state == EPOINT_STATE_IN_SETUP)
1621 /* request MORE info, if not already at higher state */
1622 new_state(EPOINT_STATE_IN_OVERLAP);
1623 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1624 message_put(message);
1625 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1629 /* port MESSAGE_INFORMATION */
1630 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1632 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1636 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1639 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1644 /* if vbox_play is done, the information are just used as they come */
1646 if (e_action->index == ACTION_VBOX_PLAY)
1648 /* concat dialing string */
1649 SCAT(e_dialinginfo.id, param->information.id);
1654 /* keypad when disconnect but in connected mode */
1655 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode)
1657 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1658 /* processing keypad function */
1659 if (param->information.id[0] == '0')
1666 /* keypad when connected */
1667 if (e_state == EPOINT_STATE_CONNECT)
1671 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1672 /* processing keypad function */
1673 if (param->information.id[0] == '0')
1677 if (param->information.id[0])
1678 keypad_function(param->information.id[0]);
1681 if (e_ext.number[0])
1682 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1684 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1689 if (e_state != EPOINT_STATE_IN_OVERLAP)
1691 if (e_ext.number[0])
1692 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1694 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1698 if (!param->information.id[0])
1700 if (e_dialinginfo.id[0]=='\0' && !e_action)
1702 set_tone(portlist, "dialing");
1705 if (e_action->index==ACTION_OUTDIAL
1706 || e_action->index==ACTION_EXTERNAL)
1709 set_tone(portlist, "dialing");
1710 else if (!e_extdialing[0])
1711 set_tone(portlist, "dialing");
1713 /* concat dialing string */
1714 SCAT(e_dialinginfo.id, param->information.id);
1718 /* port MESSAGE_DTMF */
1719 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1721 /* only if dtmf detection is enabled */
1724 trace_header("DTMF (disabled)", DIRECTION_IN);
1728 trace_header("DTMF", DIRECTION_IN);
1729 add_trace("digit", NULL, "%c", param->dtmf);
1733 NOTE: vbox is now handled due to overlap state
1734 /* if vbox_play is done, the dtmf digits are just used as they come */
1736 if (e_action->index == ACTION_VBOX_PLAY)
1738 /* concat dialing string */
1739 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id))
1741 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1742 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1745 /* continue to process *X# sequences */
1749 /* check for *X# sequence */
1750 if (e_state == EPOINT_STATE_CONNECT)
1752 if (e_dtmf_time+3 < now)
1754 /* the last digit was too far in the past to be a sequence */
1755 if (param->dtmf == '*')
1756 /* only start is allowed in the sequence */
1762 /* we have a sequence of digits, see what we got */
1763 if (param->dtmf == '*')
1765 else if (param->dtmf>='0' && param->dtmf<='9')
1767 /* we need to have a star before we receive the digit of the sequence */
1768 if (e_dtmf_last == '*')
1769 e_dtmf_last = param->dtmf;
1770 } else if (param->dtmf == '#')
1773 if (e_dtmf_last>='0' && e_dtmf_last<='9')
1775 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1776 if (e_dtmf_last == '0')
1781 /* processing keypad function */
1783 keypad_function(e_dtmf_last);
1789 /* set last time of dtmf */
1794 /* check for ## hookflash during dialing */
1796 if (e_action->index==ACTION_PASSWORD
1797 || e_action->index==ACTION_PASSWORD_WRITE)
1799 if (param->dtmf=='#') /* current digit is '#' */
1801 if (e_state==EPOINT_STATE_IN_DISCONNECT
1802 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) /* when disconnected, just #. when dialing, ##. */
1819 /* dialing using dtmf digit */
1820 if (e_state==EPOINT_STATE_IN_OVERLAP)// && e_state==e_connectedmode)
1822 if (e_dialinginfo.id[0]=='\0' && !e_action)
1824 set_tone(portlist, "dialing");
1826 /* concat dialing string */
1827 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id))
1829 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1830 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1836 /* port MESSAGE_CRYPT */
1837 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1839 /* send crypt response to cryptman */
1840 if (param->crypt.type == CR_MESSAGE_IND)
1841 cryptman_msg2man(param->crypt.data, param->crypt.len);
1843 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1846 /* port MESSAGE_OVERLAP */
1847 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1849 struct lcr_msg *message;
1851 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1853 /* signal to call tool */
1854 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1856 if (e_dialing_queue[0] && portlist)
1858 /* send what we have not dialed yet, because we had no setup complete */
1859 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1860 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1861 SCPY(message->param.information.id, e_dialing_queue);
1862 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1863 message_put(message);
1864 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1865 e_dialing_queue[0] = '\0';
1867 /* check if pattern is available */
1868 if (!ea_endpoint->ep_portlist->next && portlist->early_b) /* one port_list relation and tones available */
1870 /* indicate patterns */
1871 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1872 message_put(message);
1874 /* connect audio, if not already */
1875 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1876 message->param.audiopath = 1;
1877 message_put(message);
1880 /* indicate no patterns */
1881 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1882 message_put(message);
1884 /* disconnect audio, if not already */
1885 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1886 message->param.audiopath = 0;
1887 message_put(message);
1889 new_state(EPOINT_STATE_OUT_OVERLAP);
1890 /* if we are in a join */
1891 if (ea_endpoint->ep_join_id)
1893 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1894 memcpy(&message->param, param, sizeof(union parameter));
1895 message_put(message);
1899 /* port MESSAGE_PROCEEDING */
1900 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1902 struct lcr_msg *message;
1904 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1906 /* signal to call tool */
1907 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1909 e_state = EPOINT_STATE_OUT_PROCEEDING;
1910 /* check if pattern is availatle */
1911 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) /* one port_list relation and tones available */
1913 /* indicate patterns */
1914 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1915 message_put(message);
1917 /* connect audio, if not already */
1918 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1919 message->param.audiopath = 1;
1920 message_put(message);
1923 /* indicate no patterns */
1924 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1925 message_put(message);
1927 /* disconnect audio, if not already */
1928 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1929 message->param.audiopath = 0;
1930 message_put(message);
1932 /* if we are in a call */
1933 if (ea_endpoint->ep_join_id)
1935 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1936 memcpy(&message->param, param, sizeof(union parameter));
1937 message_put(message);
1941 /* port MESSAGE_ALERTING */
1942 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1944 struct lcr_msg *message;
1946 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1948 /* signal to call tool */
1949 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1951 new_state(EPOINT_STATE_OUT_ALERTING);
1952 /* check if pattern is available */
1953 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) /* one port_list relation and tones available */
1955 /* indicate patterns */
1956 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1957 message_put(message);
1959 /* connect audio, if not already */
1960 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1961 message->param.audiopath = 1;
1962 message_put(message);
1965 /* indicate no patterns */
1966 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1967 message_put(message);
1969 /* disconnect audio, if not already */
1970 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1971 message->param.audiopath = 0;
1972 message_put(message);
1974 /* if we are in a call */
1975 if (ea_endpoint->ep_join_id)
1977 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1978 memcpy(&message->param, param, sizeof(union parameter));
1979 message_put(message);
1983 /* port MESSAGE_CONNECT */
1984 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1986 struct lcr_msg *message;
1988 unsigned long port_id = portlist->port_id;
1989 struct port_list *tportlist;
1991 struct interface *interface;
1993 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1995 /* signal to call tool */
1996 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1998 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1999 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2000 while(ea_endpoint->ep_portlist->next) /* as long as we have at least two ports */
2002 tportlist = ea_endpoint->ep_portlist;
2003 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2004 tportlist = tportlist->next;
2005 if (tportlist->port_id == port_id)
2006 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2007 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2008 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
2009 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2010 message_put(message);
2011 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
2012 ea_endpoint->free_portlist(tportlist);
2014 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2018 /* screen incoming connected id */
2019 interface = interface_first;
2022 if (!strcmp(e_connectinfo.interface, interface->name))
2026 interface = interface->next;
2029 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
2031 /* screen connected name */
2033 SCPY(e_connectinfo.name, e_ext.name);
2035 /* add internal id to colp */
2036 SCPY(e_connectinfo.extension, e_ext.number);
2038 /* we store the connected port number */
2039 SCPY(e_extension_interface, e_connectinfo.interface);
2041 /* for internal and am calls, we get the extension's id */
2042 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE)
2044 SCPY(e_connectinfo.id, e_ext.callerid);
2045 SCPY(e_connectinfo.extension, e_ext.number);
2046 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2047 e_connectinfo.ntype = e_ext.callerid_type;
2048 e_connectinfo.present = e_ext.callerid_present;
2050 if (portlist->port_type==PORT_TYPE_VBOX_OUT)
2052 e_connectinfo.itype = INFO_ITYPE_VBOX;
2053 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2056 new_state(EPOINT_STATE_CONNECT);
2058 /* set volume of rx and tx */
2059 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2061 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2062 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2063 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2064 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2065 message_put(message);
2068 e_cfnr_call = e_cfnr_release = 0;
2069 if (e_ext.number[0])
2070 e_dtmf = 1; /* allow dtmf */
2073 /* other calls with no caller id (or not available for the extension) and force colp */
2074 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE)
2076 e_connectinfo.present = INFO_PRESENT_NOTAVAIL;
2077 if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) /* external extension answered */
2079 port = find_port_id(portlist->port_id);
2082 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2083 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2088 /* send connect to join */
2089 if (ea_endpoint->ep_join_id)
2091 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2092 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2093 message_put(message);
2095 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2096 message->param.audiopath = 1;
2097 message_put(message);
2098 } else if (!e_adminid)
2101 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2102 SCPY(e_ext.number, e_cbcaller);
2103 new_state(EPOINT_STATE_IN_OVERLAP);
2104 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2106 /* get extension's info about terminal */
2107 if (!read_extension(&e_ext, e_ext.number))
2109 /* extension doesn't exist */
2110 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2111 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2112 new_state(EPOINT_STATE_OUT_DISCONNECT);
2113 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2117 /* put prefix in front of e_cbdialing */
2118 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2119 SCPY(e_dialinginfo.id, buffer);
2120 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2121 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2123 /* use caller id (or if exist: id_next_call) for this call */
2124 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2125 SCPY(e_callerinfo.extension, e_ext.number);
2126 if (e_ext.id_next_call_present >= 0)
2128 SCPY(e_callerinfo.id, e_ext.id_next_call);
2129 e_callerinfo.present = e_ext.id_next_call_present;
2130 e_callerinfo.ntype = e_ext.id_next_call_type;
2131 e_ext.id_next_call_present = -1;
2132 /* extension is written */
2133 write_extension(&e_ext, e_ext.number);
2136 SCPY(e_callerinfo.id, e_ext.callerid);
2137 e_callerinfo.present = e_ext.callerid_present;
2138 e_callerinfo.ntype = e_ext.callerid_type;
2141 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2144 /* check if caller id is NOT authenticated */
2145 if (!parse_callbackauth(e_ext.number, &e_callbackinfo))
2147 /* make call state to enter password */
2148 new_state(EPOINT_STATE_IN_OVERLAP);
2149 e_action = &action_password_write;
2150 e_match_timeout = 0;
2151 e_match_to_action = NULL;
2152 e_dialinginfo.id[0] = '\0';
2153 e_extdialing = strchr(e_dialinginfo.id, '\0');
2154 e_password_timeout = now+20;
2158 /* incoming call (callback) */
2159 e_ruleset = ruleset_main;
2161 e_rule = e_ruleset->rule_first;
2163 e_extdialing = e_dialinginfo.id;
2164 if (e_dialinginfo.id[0])
2166 set_tone(portlist, "dialing");
2170 set_tone(portlist, "dialpbx");
2173 } else /* testcall */
2175 set_tone(portlist, "hold");
2178 /* start recording if enabled, not when answering machine answers */
2179 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))
2181 /* check if we are a terminal */
2182 if (e_ext.number[0] == '\0')
2183 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2186 port = find_port_id(portlist->port_id);
2188 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2193 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2194 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2196 struct lcr_msg *message;
2198 unsigned long port_id = portlist->port_id;
2202 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2204 /* signal to call tool */
2205 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2207 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2208 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE)// || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2210 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2215 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);
2216 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2217 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2219 /* check if we have more than one portlist relation and we just ignore the disconnect */
2220 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next)
2222 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2223 portlist = ea_endpoint->ep_portlist;
2226 if (portlist->port_id == port_id)
2228 portlist = portlist->next;
2231 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2232 if (message_type != MESSAGE_RELEASE)
2234 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2235 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2236 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2237 message_put(message);
2238 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2240 ea_endpoint->free_portlist(portlist);
2241 return; /* one relation removed */
2243 if (e_state == EPOINT_STATE_CONNECT)
2245 /* use cause from port after connect */
2246 cause = param->disconnectinfo.cause;
2247 location = param->disconnectinfo.location;
2250 /* use multipoint cause if no connect yet */
2251 if (e_multipoint_cause)
2253 cause = e_multipoint_cause;
2254 location = e_multipoint_location;
2257 cause = CAUSE_NOUSER;
2258 location = LOCATION_PRIVATE_LOCAL;
2262 e_cfnr_call = e_cfnr_release = 0;
2264 /* process hangup */
2265 process_hangup(e_join_cause, e_join_location);
2266 e_multipoint_cause = 0;
2267 e_multipoint_location = 0;
2269 if (message_type == MESSAGE_DISCONNECT)
2271 /* tone to disconnected end */
2272 SPRINT(buffer, "cause_%02x", cause);
2273 if (ea_endpoint->ep_portlist)
2274 set_tone(ea_endpoint->ep_portlist, buffer);
2276 new_state(EPOINT_STATE_IN_DISCONNECT);
2279 if (ea_endpoint->ep_join_id)
2281 int haspatterns = 0;
2282 /* check if pattern is available */
2283 if (ea_endpoint->ep_portlist)
2284 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2285 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
2286 && message_type != MESSAGE_RELEASE) // if we release, we are done
2290 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2291 /* indicate patterns */
2292 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2293 message_put(message);
2294 /* connect audio, if not already */
2295 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2296 message->param.audiopath = 1;
2297 message_put(message);
2298 /* send disconnect */
2299 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2300 memcpy(&message->param, param, sizeof(union parameter));
2301 message_put(message);
2302 /* disable encryption if disconnected */
2303 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2305 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2309 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2312 if (message_type == MESSAGE_RELEASE)
2313 ea_endpoint->free_portlist(portlist);
2314 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */
2315 return; /* must exit here */
2318 /* port MESSAGE_TIMEOUT */
2319 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2323 trace_header("TIMEOUT", DIRECTION_IN);
2324 message_type = MESSAGE_DISCONNECT;
2325 switch (param->state)
2327 case PORT_STATE_OUT_SETUP:
2328 case PORT_STATE_OUT_OVERLAP:
2329 add_trace("state", NULL, "outgoing setup/dialing");
2331 /* no user responding */
2332 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2333 return; /* must exit here */
2335 case PORT_STATE_IN_SETUP:
2336 case PORT_STATE_IN_OVERLAP:
2337 add_trace("state", NULL, "incoming setup/dialing");
2338 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2339 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2342 case PORT_STATE_OUT_PROCEEDING:
2343 add_trace("state", NULL, "outgoing proceeding");
2345 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2346 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2347 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2348 return; /* must exit here */
2350 case PORT_STATE_IN_PROCEEDING:
2351 add_trace("state", NULL, "incoming proceeding");
2352 param->disconnectinfo.cause = CAUSE_NOUSER;
2353 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2356 case PORT_STATE_OUT_ALERTING:
2357 add_trace("state", NULL, "outgoing alerting");
2359 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2360 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2361 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2362 return; /* must exit here */
2364 case PORT_STATE_CONNECT:
2365 add_trace("state", NULL, "connect");
2367 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2368 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2369 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2370 return; /* must exit here */
2372 case PORT_STATE_IN_ALERTING:
2373 add_trace("state", NULL, "incoming alerting");
2374 param->disconnectinfo.cause = CAUSE_NOANSWER;
2375 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2378 case PORT_STATE_IN_DISCONNECT:
2379 case PORT_STATE_OUT_DISCONNECT:
2380 add_trace("state", NULL, "disconnect");
2382 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2383 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2384 return; /* must exit here */
2387 param->disconnectinfo.cause = 31; /* normal unspecified */
2388 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2391 /* release call, disconnect isdn */
2393 new_state(EPOINT_STATE_OUT_DISCONNECT);
2394 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2395 SCPY(e_tone, cause);
2398 set_tone(portlist, cause);
2399 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2400 portlist = portlist->next;
2402 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2405 /* port MESSAGE_NOTIFY */
2406 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2408 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2410 struct lcr_msg *message;
2414 /* signal to call tool */
2415 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);
2416 if (param->notifyinfo.notify)
2418 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2421 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2422 if (param->notifyinfo.local) switch(param->notifyinfo.notify)
2424 case INFO_NOTIFY_REMOTE_HOLD:
2425 case INFO_NOTIFY_USER_SUSPENDED:
2426 /* tell call about it */
2427 if (ea_endpoint->ep_join_id)
2429 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2430 message->param.audiopath = 0;
2431 message_put(message);
2435 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2436 case INFO_NOTIFY_USER_RESUMED:
2437 /* set volume of rx and tx */
2438 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2439 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2442 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2443 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2444 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2445 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2446 message_put(message);
2448 /* set current tone */
2450 set_tone(portlist, e_tone);
2451 /* tell call about it */
2452 if (ea_endpoint->ep_join_id)
2454 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2455 message->param.audiopath = 1;
2456 message_put(message);
2461 /* get name of notify */
2462 switch(param->notifyinfo.notify)
2468 logtext = "USER_SUSPENDED";
2471 logtext = "BEARER_SERVICE_CHANGED";
2474 logtext = "USER_RESUMED";
2477 logtext = "CONFERENCE_ESTABLISHED";
2480 logtext = "CONFERENCE_DISCONNECTED";
2483 logtext = "OTHER_PARTY_ADDED";
2486 logtext = "ISOLATED";
2489 logtext = "REATTACHED";
2492 logtext = "OTHER_PARTY_ISOLATED";
2495 logtext = "OTHER_PARTY_REATTACHED";
2498 logtext = "OTHER_PARTY_SPLIT";
2501 logtext = "OTHER_PARTY_DISCONNECTED";
2504 logtext = "CONFERENCE_FLOATING";
2507 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2510 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2513 logtext = "CALL_IS_A_WAITING_CALL";
2516 logtext = "DIVERSION_ACTIVATED";
2519 logtext = "RESERVED_CT_1";
2522 logtext = "RESERVED_CT_2";
2525 logtext = "REVERSE_CHARGING";
2528 logtext = "REMOTE_HOLD";
2531 logtext = "REMOTE_RETRIEVAL";
2534 logtext = "CALL_IS_DIVERTING";
2537 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2542 /* notify call if available */
2543 if (ea_endpoint->ep_join_id)
2545 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2546 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2547 message_put(message);
2552 /* port MESSAGE_FACILITY */
2553 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2555 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2557 struct lcr_msg *message;
2559 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2560 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2561 message_put(message);
2564 /* port MESSAGE_SUSPEND */
2565 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2566 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2568 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2570 /* epoint is now parked */
2571 ea_endpoint->ep_park = 1;
2572 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2573 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2575 /* remove port relation */
2576 ea_endpoint->free_portlist(portlist);
2579 /* port MESSAGE_RESUME */
2580 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2581 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2583 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2585 /* epoint is now resumed */
2586 ea_endpoint->ep_park = 0;
2591 /* port sends message to the endpoint
2593 void EndpointAppPBX::ea_message_port(unsigned long port_id, int message_type, union parameter *param)
2595 struct port_list *portlist;
2596 struct lcr_msg *message;
2598 portlist = ea_endpoint->ep_portlist;
2601 if (port_id == portlist->port_id)
2603 portlist = portlist->next;
2607 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);
2611 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2612 switch(message_type)
2614 case MESSAGE_DATA: /* data from port */
2615 /* check if there is a call */
2616 if (!ea_endpoint->ep_join_id)
2618 /* continue if only one portlist */
2619 if (ea_endpoint->ep_portlist->next != NULL)
2621 /* forward message */
2622 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2625 case MESSAGE_TONE_EOF: /* tone is end of file */
2626 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2629 if (e_action->index == ACTION_VBOX_PLAY)
2633 if (e_action->index == ACTION_EFI)
2640 case MESSAGE_TONE_COUNTER: /* counter info received */
2641 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);
2643 if (e_action->index == ACTION_VBOX_PLAY)
2645 e_vbox_counter = param->counter.current;
2646 if (param->counter.max >= 0)
2647 e_vbox_counter_max = param->counter.max;
2651 /* PORT sends SETUP message */
2653 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);
2654 if (e_state!=EPOINT_STATE_IDLE)
2656 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2659 port_setup(portlist, message_type, param);
2662 /* PORT sends INFORMATION message */
2663 case MESSAGE_INFORMATION: /* additional digits received */
2664 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);
2665 port_information(portlist, message_type, param);
2668 /* PORT sends FACILITY message */
2669 case MESSAGE_FACILITY:
2670 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2671 port_facility(portlist, message_type, param);
2674 /* PORT sends DTMF message */
2675 case MESSAGE_DTMF: /* dtmf digits received */
2676 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);
2677 port_dtmf(portlist, message_type, param);
2680 /* PORT sends CRYPT message */
2681 case MESSAGE_CRYPT: /* crypt response received */
2682 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2683 port_crypt(portlist, message_type, param);
2686 /* PORT sends MORE message */
2687 case MESSAGE_OVERLAP:
2688 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);
2689 if (e_state != EPOINT_STATE_OUT_SETUP)
2691 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);
2694 port_overlap(portlist, message_type, param);
2697 /* PORT sends PROCEEDING message */
2698 case MESSAGE_PROCEEDING: /* port is proceeding */
2699 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);
2700 if (e_state!=EPOINT_STATE_OUT_SETUP
2701 && e_state!=EPOINT_STATE_OUT_OVERLAP)
2703 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);
2706 port_proceeding(portlist, message_type, param);
2709 /* PORT sends ALERTING message */
2710 case MESSAGE_ALERTING:
2711 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);
2712 if (e_state!=EPOINT_STATE_OUT_SETUP
2713 && e_state!=EPOINT_STATE_OUT_OVERLAP
2714 && e_state!=EPOINT_STATE_OUT_PROCEEDING)
2716 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);
2719 port_alerting(portlist, message_type, param);
2722 /* PORT sends CONNECT message */
2723 case MESSAGE_CONNECT:
2724 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);
2725 if (e_state!=EPOINT_STATE_OUT_SETUP
2726 && e_state!=EPOINT_STATE_OUT_OVERLAP
2727 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2728 && e_state!=EPOINT_STATE_OUT_ALERTING)
2730 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2733 port_connect(portlist, message_type, param);
2736 /* PORT sends DISCONNECT message */
2737 case MESSAGE_DISCONNECT: /* port is disconnected */
2738 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);
2739 port_disconnect_release(portlist, message_type, param);
2742 /* PORT sends a RELEASE message */
2743 case MESSAGE_RELEASE: /* port releases */
2744 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);
2745 /* portlist is release at port_disconnect_release, thanx Paul */
2746 port_disconnect_release(portlist, message_type, param);
2749 /* PORT sends a TIMEOUT message */
2750 case MESSAGE_TIMEOUT:
2751 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);
2752 port_timeout(portlist, message_type, param);
2753 break; /* release */
2755 /* PORT sends a NOTIFY message */
2756 case MESSAGE_NOTIFY:
2757 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);
2758 port_notify(portlist, message_type, param);
2761 /* PORT sends a SUSPEND message */
2762 case MESSAGE_SUSPEND:
2763 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);
2764 port_suspend(portlist, message_type, param);
2765 break; /* suspend */
2767 /* PORT sends a RESUME message */
2768 case MESSAGE_RESUME:
2769 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);
2770 port_resume(portlist, message_type, param);
2774 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2775 /* port assigns bchannel */
2776 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2777 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);
2778 /* only one port is expected to be connected to bchannel */
2779 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2780 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2786 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);
2789 /* Note: this endpoint may be destroyed, so we MUST return */
2793 /* messages from join
2795 /* join MESSAGE_CRYPT */
2796 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2798 switch(param->crypt.type)
2800 /* message from remote port to "crypt manager" */
2801 case CU_ACTK_REQ: /* activate key-exchange */
2802 case CU_ACTS_REQ: /* activate shared key */
2803 case CU_DACT_REQ: /* deactivate */
2804 case CU_INFO_REQ: /* request last info message */
2805 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2808 /* message from "crypt manager" to user */
2809 case CU_ACTK_CONF: /* key-echange done */
2810 case CU_ACTS_CONF: /* shared key done */
2811 case CU_DACT_CONF: /* deactivated */
2812 case CU_DACT_IND: /* deactivated */
2813 case CU_ERROR_IND: /* receive error message */
2814 case CU_INFO_IND: /* receive info message */
2815 case CU_INFO_CONF: /* receive info message */
2816 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2820 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);
2824 /* join MESSAGE_INFORMATION */
2825 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2827 struct lcr_msg *message;
2833 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2834 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2835 message_put(message);
2836 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2837 portlist = portlist->next;
2841 /* join MESSAGE_FACILITY */
2842 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2844 struct lcr_msg *message;
2846 if (!e_ext.facility && e_ext.number[0])
2853 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2854 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2855 message_put(message);
2856 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2857 portlist = portlist->next;
2861 /* join MESSAGE_MORE */
2862 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2864 struct lcr_msg *message;
2866 new_state(EPOINT_STATE_IN_OVERLAP);
2869 if (e_join_pattern && e_ext.own_setup)
2871 /* disconnect audio */
2872 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2873 message->param.audiopath = 0;
2874 message_put(message);
2876 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
2878 if (e_dialinginfo.id[0])
2879 set_tone(portlist, "dialing");
2881 set_tone(portlist, "dialtone");
2884 if (e_ext.number[0])
2885 set_tone(portlist, "dialpbx");
2887 set_tone(portlist, "dialtone");
2890 /* join MESSAGE_PROCEEDING */
2891 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2893 struct lcr_msg *message;
2895 new_state(EPOINT_STATE_IN_PROCEEDING);
2897 /* own proceeding tone */
2900 /* connect / disconnect audio */
2901 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2902 if (e_ext.own_proceeding)
2903 message->param.audiopath = 0;
2905 message->param.audiopath = 1;
2906 message_put(message);
2908 // UCPY(e_join_tone, "proceeding");
2911 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2912 message_put(message);
2913 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2915 set_tone(portlist, "proceeding");
2918 /* join MESSAGE_ALERTING */
2919 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2921 struct lcr_msg *message;
2923 new_state(EPOINT_STATE_IN_ALERTING);
2925 /* own alerting tone */
2928 /* connect / disconnect audio */
2929 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2930 if (e_ext.own_alerting)
2931 message->param.audiopath = 0;
2933 message->param.audiopath = 1;
2934 message_put(message);
2938 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2939 message_put(message);
2940 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2942 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
2944 set_tone(portlist, "ringing");
2947 if (e_ext.number[0])
2948 set_tone(portlist, "ringpbx");
2950 set_tone(portlist, "ringing");
2953 /* join MESSAGE_CONNECT */
2954 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2956 struct lcr_msg *message;
2958 new_state(EPOINT_STATE_CONNECT);
2959 // UCPY(e_join_tone, "");
2960 if (e_ext.number[0])
2961 e_dtmf = 1; /* allow dtmf */
2963 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2966 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2967 memcpy(&message->param, param, sizeof(union parameter));
2969 /* screen clip if prefix is required */
2970 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0])
2972 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2973 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2974 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2977 /* use internal caller id */
2978 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore))
2980 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2981 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2984 /* handle restricted caller ids */
2985 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);
2986 /* display callerid if desired for extension */
2987 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));
2989 /* use conp, if enabld */
2990 // if (!e_ext.centrex)
2991 // message->param.connectinfo.name[0] = '\0';
2994 message_put(message);
2995 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2997 set_tone(portlist, NULL);
2999 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3000 message->param.audiopath = 1;
3001 message_put(message);
3005 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3006 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3009 struct lcr_msg *message;
3010 struct port_list *portlist = NULL;
3013 /* be sure that we are active */
3015 e_tx_state = NOTIFY_STATE_ACTIVE;
3017 /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
3018 if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1))
3020 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
3022 /* set time for power dialing */
3023 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
3026 /* set redial tone */
3027 if (ea_endpoint->ep_portlist)
3031 set_tone(ea_endpoint->ep_portlist, "redial");
3032 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);
3033 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3034 if (e_state==EPOINT_STATE_IN_OVERLAP)
3036 new_state(EPOINT_STATE_IN_PROCEEDING);
3037 if (ea_endpoint->ep_portlist)
3039 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3040 message_put(message);
3041 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3043 /* caused the error, that the first knock sound was not there */
3044 /* set_tone(portlist, "proceeding"); */
3046 /* send display of powerdialing */
3047 if (e_ext.display_dialing)
3049 portlist = ea_endpoint->ep_portlist;
3052 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3054 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3056 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3057 message_put(message);
3058 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3059 portlist = portlist->next;
3068 if ((e_state!=EPOINT_STATE_CONNECT
3069 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3070 && e_state!=EPOINT_STATE_IN_OVERLAP
3071 && e_state!=EPOINT_STATE_IN_PROCEEDING
3072 && e_state!=EPOINT_STATE_IN_ALERTING)
3073 || !ea_endpoint->ep_portlist) /* or no port */
3075 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3076 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */
3077 return; /* must exit here */
3082 e_join_cause = param->disconnectinfo.cause;
3083 e_join_location = param->disconnectinfo.location;
3086 /* on release we need the audio again! */
3087 if (message_type == MESSAGE_RELEASE)
3090 ea_endpoint->ep_join_id = 0;
3092 /* disconnect and select tone */
3093 new_state(EPOINT_STATE_OUT_DISCONNECT);
3094 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3095 /* if own_cause, we must release the join */
3096 if (e_ext.own_cause /* own cause */
3097 || !e_join_pattern) /* no patterns */
3099 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);
3100 if (message_type != MESSAGE_RELEASE)
3101 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
3103 } else /* else we enable audio */
3105 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3106 message->param.audiopath = 1;
3107 message_put(message);
3109 /* send disconnect message */
3110 SCPY(e_tone, cause);
3111 portlist = ea_endpoint->ep_portlist;
3114 set_tone(portlist, cause);
3115 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3116 portlist = portlist->next;
3120 /* join MESSAGE_SETUP */
3121 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3123 struct lcr_msg *message;
3124 // struct interface *interface;
3126 /* if we already in setup state, we just update the dialing with new digits */
3127 if (e_state == EPOINT_STATE_OUT_SETUP
3128 || e_state == EPOINT_STATE_OUT_OVERLAP)
3130 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3131 /* if digits changed, what we have already dialed */
3132 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id)))
3134 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);
3135 /* release all ports */
3136 while((portlist = ea_endpoint->ep_portlist))
3138 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3139 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3140 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3141 message_put(message);
3142 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3143 ea_endpoint->free_portlist(portlist);
3146 /* disconnect audio */
3147 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3148 message->param.audiopath = 0;
3149 message_put(message);
3151 /* get dialing info */
3152 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3153 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3154 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3155 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3156 new_state(EPOINT_STATE_OUT_OVERLAP);
3159 e_redial = now_d + 1; /* set redial one second in the future */
3162 /* if we have a pending redial, so we just adjust the dialing number */
3165 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);
3166 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3169 if (!ea_endpoint->ep_portlist)
3171 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3173 if (ea_endpoint->ep_portlist->next)
3175 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3177 if (e_state == EPOINT_STATE_OUT_SETUP)
3180 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);
3181 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3185 /* get what we have not dialed yet */
3186 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));
3187 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3188 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3189 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3190 message_put(message);
3191 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3193 /* always store what we have dialed or queued */
3194 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3198 if (e_state != EPOINT_STATE_IDLE)
3200 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3203 /* if an internal extension is dialed, copy that number */
3204 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3205 SCPY(e_ext.number, param->setup.dialinginfo.id);
3206 /* if an internal extension is dialed, get extension's info about caller */
3207 if (e_ext.number[0])
3209 if (!read_extension(&e_ext, e_ext.number))
3211 e_ext.number[0] = '\0';
3212 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3216 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3217 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3218 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3219 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3221 /* process (voice over) data calls */
3222 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO)
3224 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3225 memset(&e_capainfo, 0, sizeof(e_capainfo));
3226 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3227 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3228 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3231 new_state(EPOINT_STATE_OUT_SETUP);
3232 /* call special setup routine */
3236 /* join MESSAGE_mISDNSIGNAL */
3237 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3239 struct lcr_msg *message;
3243 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3244 memcpy(&message->param, param, sizeof(union parameter));
3245 message_put(message);
3246 portlist = portlist->next;
3250 /* join MESSAGE_NOTIFY */
3251 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3253 struct lcr_msg *message;
3256 if (param->notifyinfo.notify)
3258 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3259 // /* if notification was generated locally, we turn hold music on/off */
3260 // if (param->notifyinfo.local)
3261 // 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)
3266 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND)
3268 if (!strcmp(e_tone, "hold")) // don't interrupt other tones
3272 set_tone(portlist, "");
3273 portlist = portlist->next;
3276 portlist = ea_endpoint->ep_portlist;
3281 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND)
3285 set_tone(portlist, "hold");
3286 portlist = portlist->next;
3288 portlist = ea_endpoint->ep_portlist;
3293 /* save new state */
3294 e_tx_state = new_state;
3297 /* notify port(s) about it */
3300 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3301 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3302 /* handle restricted caller ids */
3303 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3304 /* display callerid if desired for extension */
3305 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));
3306 message_put(message);
3307 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3308 portlist = portlist->next;
3312 /* JOIN sends messages to the endpoint
3314 void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, union parameter *param)
3316 struct port_list *portlist;
3317 struct lcr_msg *message;
3321 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3325 portlist = ea_endpoint->ep_portlist;
3327 /* send MESSAGE_DATA to port */
3328 if (message_type == MESSAGE_DATA)
3330 if (join_id == ea_endpoint->ep_join_id) // still linked with JOIN
3332 /* skip if no port relation */
3335 /* skip if more than one port relation */
3338 /* forward audio data to port */
3339 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3344 // 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);
3345 switch(message_type)
3347 /* JOIN SENDS TONE message */
3349 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);
3350 set_tone(portlist, param->tone.name);
3353 /* JOIN SENDS CRYPT message */
3355 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);
3356 join_crypt(portlist, message_type, param);
3359 /* JOIN sends INFORMATION message */
3360 case MESSAGE_INFORMATION:
3361 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);
3362 join_information(portlist, message_type, param);
3365 /* JOIN sends FACILITY message */
3366 case MESSAGE_FACILITY:
3367 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);
3368 join_facility(portlist, message_type, param);
3371 /* JOIN sends OVERLAP message */
3372 case MESSAGE_OVERLAP:
3373 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received 'more info available'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3374 if (e_state!=EPOINT_STATE_IN_SETUP
3375 && e_state!=EPOINT_STATE_IN_OVERLAP)
3377 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3380 join_overlap(portlist, message_type, param);
3383 /* JOIN sends PROCEEDING message */
3384 case MESSAGE_PROCEEDING:
3385 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);
3386 if(e_state!=EPOINT_STATE_IN_OVERLAP)
3388 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3391 join_proceeding(portlist, message_type, param);
3394 /* JOIN sends ALERTING message */
3395 case MESSAGE_ALERTING:
3396 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);
3397 if (e_state!=EPOINT_STATE_IN_OVERLAP
3398 && e_state!=EPOINT_STATE_IN_PROCEEDING)
3400 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3403 join_alerting(portlist, message_type, param);
3406 /* JOIN sends CONNECT message */
3407 case MESSAGE_CONNECT:
3408 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);
3409 if (e_state!=EPOINT_STATE_IN_OVERLAP
3410 && e_state!=EPOINT_STATE_IN_PROCEEDING
3411 && e_state!=EPOINT_STATE_IN_ALERTING)
3413 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3416 join_connect(portlist, message_type, param);
3419 /* JOIN sends DISCONNECT/RELEASE message */
3420 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3421 case MESSAGE_RELEASE: /* JOIN releases */
3422 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);
3423 join_disconnect_release(message_type, param);
3426 /* JOIN sends SETUP message */
3428 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);
3429 join_setup(portlist, message_type, param);
3432 /* JOIN sends special mISDNSIGNAL message */
3433 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3434 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);
3435 join_mISDNsignal(portlist, message_type, param);
3439 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3440 /* JOIN requests bchannel */
3441 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3442 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);
3443 /* only one port is expected to be connected to bchannel */
3450 set_tone(portlist, NULL);
3451 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3452 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3456 /* JOIN has pattern available */
3457 case MESSAGE_PATTERN: /* indicating pattern available */
3458 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);
3459 if (!e_join_pattern)
3461 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3466 set_tone(portlist, NULL);
3467 portlist = portlist->next;
3469 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3470 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3471 message->param.audiopath = 1;
3472 message_put(message);
3476 /* JOIN has no pattern available */
3477 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3478 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);
3481 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3483 /* disconnect our audio tx and rx */
3484 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3485 message->param.audiopath = 0;
3486 message_put(message);
3491 /* JOIN (dunno at the moment) */
3492 case MESSAGE_REMOTE_AUDIO:
3493 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);
3494 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3495 message->param.audiopath = param->channel;
3496 message_put(message);
3500 /* JOIN sends a notify message */
3501 case MESSAGE_NOTIFY:
3502 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);
3503 join_notify(portlist, message_type, param);
3507 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);
3512 /* pick_join will connect the first incoming call found. the endpoint
3513 * will receivce a MESSAGE_CONNECT.
3515 int match_list(char *list, char *item)
3517 char *end, *next = NULL;
3519 /* no list make matching */
3525 /* eliminate white spaces */
3526 while (*list <= ' ')
3533 /* if end of list is reached, we return */
3534 if (list[0] == '\0')
3536 /* if we have more than one entry (left) */
3537 if ((end = strchr(list, ',')))
3540 next = end = strchr(list, '\0');
3541 while (*(end-1) <= ' ')
3543 /* if string part matches item */
3544 if (!strncmp(list, item, end-list))
3550 void EndpointAppPBX::pick_join(char *extensions)
3552 struct lcr_msg *message;
3553 struct port_list *portlist;
3555 class EndpointAppPBX *eapp, *found;
3557 class JoinPBX *joinpbx;
3558 struct join_relation *relation;
3561 /* find an endpoint that is ringing internally or vbox with higher priority */
3564 eapp = apppbx_first;
3567 if (eapp!=this && ea_endpoint->ep_portlist)
3569 portlist = eapp->ea_endpoint->ep_portlist;
3572 if ((port = find_port_id(portlist->port_id)))
3574 if (port->p_type == PORT_TYPE_VBOX_OUT)
3576 if (match_list(extensions, eapp->e_ext.number))
3583 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT)
3584 && port->p_state==PORT_STATE_OUT_ALERTING)
3585 if (match_list(extensions, eapp->e_ext.number))
3590 portlist = portlist->next;
3598 /* if no endpoint found */
3601 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);
3603 set_tone(ea_endpoint->ep_portlist, "cause_10");
3604 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3605 new_state(EPOINT_STATE_OUT_DISCONNECT);
3610 if (ea_endpoint->ep_join_id)
3612 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3615 if (!eapp->ea_endpoint->ep_join_id)
3617 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3620 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3623 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3626 if (join->j_type != JOIN_TYPE_PBX)
3628 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3631 joinpbx = (class JoinPBX *)join;
3632 relation = joinpbx->j_relation;
3635 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3638 while (relation->epoint_id != eapp->ea_endpoint->ep_serial)
3640 relation = relation->next;
3643 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3648 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3650 if (options.deb & DEBUG_EPOINT)
3652 class Join *debug_c = join_first;
3653 class Endpoint *debug_e = epoint_first;
3654 class Port *debug_p = port_first;
3656 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3658 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3661 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3662 debug_c = debug_c->next;
3664 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3667 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3668 debug_e = debug_e->next;
3670 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3673 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3674 debug_p = debug_p->next;
3679 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3680 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3681 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3683 /* connnecting our endpoint */
3684 new_state(EPOINT_STATE_CONNECT);
3686 set_tone(ea_endpoint->ep_portlist, NULL);
3688 /* now we send a release to the ringing endpoint */
3689 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3690 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3691 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3692 message_put(message);
3694 /* we send a connect to the join with our caller id */
3695 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3696 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3697 message->param.connectinfo.present = e_callerinfo.present;
3698 message->param.connectinfo.screen = e_callerinfo.screen;
3699 message->param.connectinfo.itype = e_callerinfo.itype;
3700 message->param.connectinfo.ntype = e_callerinfo.ntype;
3701 message_put(message);
3703 /* we send a connect to our port with the remote callerid */
3704 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3705 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3706 message->param.connectinfo.present = eapp->e_callerinfo.present;
3707 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3708 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3709 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3710 /* handle restricted caller ids */
3711 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);
3712 /* display callerid if desired for extension */
3713 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));
3714 message_put(message);
3716 /* we send a connect to the audio path (not for vbox) */
3717 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3718 message->param.audiopath = 1;
3719 message_put(message);
3721 /* beeing paranoid, we make call update */
3722 joinpbx->j_updatebridge = 1;
3724 if (options.deb & DEBUG_EPOINT)
3726 class Join *debug_c = join_first;
3727 class Endpoint *debug_e = epoint_first;
3728 class Port *debug_p = port_first;
3730 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3732 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3735 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3736 debug_c = debug_c->next;
3738 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3741 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3742 debug_e = debug_e->next;
3744 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3747 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3748 debug_p = debug_p->next;
3754 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3756 void EndpointAppPBX::join_join(void)
3758 struct lcr_msg *message;
3759 struct join_relation *our_relation, *other_relation;
3760 struct join_relation **our_relation_pointer, **other_relation_pointer;
3761 class Join *our_join, *other_join;
3762 class JoinPBX *our_joinpbx, *other_joinpbx;
3763 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3764 class Port *our_port, *other_port;
3765 class Pdss1 *our_pdss1, *other_pdss1;
3767 /* are we a candidate to join a join */
3768 our_join = find_join_id(ea_endpoint->ep_join_id);
3771 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3774 if (our_join->j_type != JOIN_TYPE_PBX)
3776 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3779 our_joinpbx = (class JoinPBX *)our_join;
3780 if (!ea_endpoint->ep_portlist)
3782 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3785 if (!e_ext.number[0])
3787 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3790 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3793 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3796 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
3798 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3801 our_pdss1 = (class Pdss1 *)our_port;
3803 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3804 other_eapp = apppbx_first;
3807 if (other_eapp == this)
3809 other_eapp = other_eapp->next;
3812 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);
3813 if (other_eapp->e_ext.number[0] /* has terminal */
3814 && other_eapp->ea_endpoint->ep_portlist /* has port */
3815 && other_eapp->ea_endpoint->ep_join_id) /* has join */
3817 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3818 if (other_port) /* port still exists */
3820 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3821 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) /* port is isdn nt-mode */
3823 other_pdss1 = (class Pdss1 *)other_port;
3824 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);
3825 if (other_pdss1->p_m_hold /* port is on hold */
3826 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3827 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3831 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3835 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3838 other_eapp = other_eapp->next;
3842 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn interface with port on hold.\n", ea_endpoint->ep_serial);
3845 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port on hold found.\n", ea_endpoint->ep_serial);
3847 /* if we have the same join */
3848 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id)
3850 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we an the other have the same join.\n", ea_endpoint->ep_serial);
3853 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3856 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3859 if (other_join->j_type != JOIN_TYPE_PBX)
3861 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3864 other_joinpbx = (class JoinPBX *)other_join;
3865 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline)
3867 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3871 /* remove relation to endpoint for join on hold */
3872 other_relation = other_joinpbx->j_relation;
3873 other_relation_pointer = &other_joinpbx->j_relation;
3874 while(other_relation)
3876 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial)
3878 /* detach other endpoint on hold */
3879 *other_relation_pointer = other_relation->next;
3880 FREE(other_relation, sizeof(struct join_relation));
3882 other_relation = *other_relation_pointer;
3883 other_eapp->ea_endpoint->ep_join_id = 0;
3887 /* change join/hold pointer of endpoint to the new join */
3888 temp_epoint = find_epoint_id(other_relation->epoint_id);
3891 if (temp_epoint->ep_join_id == other_join->j_serial)
3892 temp_epoint->ep_join_id = our_join->j_serial;
3895 other_relation_pointer = &other_relation->next;
3896 other_relation = other_relation->next;
3898 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3900 /* join call relations */
3901 our_relation = our_joinpbx->j_relation;
3902 our_relation_pointer = &our_joinpbx->j_relation;
3905 our_relation_pointer = &our_relation->next;
3906 our_relation = our_relation->next;
3908 *our_relation_pointer = other_joinpbx->j_relation;
3909 other_joinpbx->j_relation = NULL;
3910 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3912 /* release endpoint on hold */
3913 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3914 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3915 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3916 message_put(message);
3918 /* if we are not a partyline, we get partyline state from other join */
3919 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3921 /* remove empty join */
3923 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3925 /* mixer must update */
3926 our_joinpbx->j_updatebridge = 1; /* update mixer flag */
3928 /* we send a retrieve to that endpoint */
3929 // mixer will update the hold-state of the join and send it to the endpoints is changes
3933 /* check if we have an external call
3934 * this is used to check for encryption ability
3936 int EndpointAppPBX::check_external(char **errstr, class Port **port)
3938 struct join_relation *relation;
3940 class JoinPBX *joinpbx;
3941 class Endpoint *epoint;
3943 /* some paranoia check */
3944 if (!ea_endpoint->ep_portlist)
3946 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3947 *errstr = "No Call";
3950 if (!e_ext.number[0])
3952 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3953 *errstr = "No Call";
3957 /* check if we have a join with 2 parties */
3958 join = find_join_id(ea_endpoint->ep_join_id);
3961 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3962 *errstr = "No Call";
3965 if (join->j_type != JOIN_TYPE_PBX)
3967 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3968 *errstr = "No PBX Call";
3971 joinpbx = (class JoinPBX *)join;
3972 relation = joinpbx->j_relation;
3975 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3976 *errstr = "No Call";
3979 if (!relation->next)
3981 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3982 *errstr = "No Call";
3985 if (relation->next->next)
3987 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3988 *errstr = "Err: Conference";
3991 if (relation->epoint_id == ea_endpoint->ep_serial)
3993 relation = relation->next;
3994 if (relation->epoint_id == ea_endpoint->ep_serial)
3996 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3997 *errstr = "Software Error";
4002 /* check remote port for external call */
4003 epoint = find_epoint_id(relation->epoint_id);
4006 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4007 *errstr = "No Call";
4010 if (!epoint->ep_portlist)
4012 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4013 *errstr = "No Call";
4016 *port = find_port_id(epoint->ep_portlist->port_id);
4019 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4020 *errstr = "No Call";
4023 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) /* port is not external isdn */
4025 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4026 *errstr = "No Ext Call";
4029 if ((*port)->p_state != PORT_STATE_CONNECT)
4031 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4032 *errstr = "No Ext Connect";
4038 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned long port_id, int dir)
4040 char *logtext = "unknown";
4043 switch(message_type)
4046 trace_header("SETUP", dir);
4047 if (dir == DIRECTION_OUT)
4048 add_trace("to", NULL, "CH(%lu)", port_id);
4049 if (dir == DIRECTION_IN)
4050 add_trace("from", NULL, "CH(%lu)", port_id);
4051 if (param->setup.callerinfo.extension[0])
4052 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4053 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4054 switch(param->setup.callerinfo.present)
4056 case INFO_PRESENT_RESTRICTED:
4057 add_trace("caller id", "present", "restricted");
4059 case INFO_PRESENT_ALLOWED:
4060 add_trace("caller id", "present", "allowed");
4063 add_trace("caller id", "present", "not available");
4065 if (param->setup.redirinfo.id[0])
4067 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4068 switch(param->setup.redirinfo.present)
4070 case INFO_PRESENT_RESTRICTED:
4071 add_trace("redir'ing", "present", "restricted");
4073 case INFO_PRESENT_ALLOWED:
4074 add_trace("redir'ing", "present", "allowed");
4077 add_trace("redir'ing", "present", "not available");
4080 if (param->setup.dialinginfo.id[0])
4081 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4085 case MESSAGE_OVERLAP:
4086 trace_header("SETUP ACKNOWLEDGE", dir);
4087 if (dir == DIRECTION_OUT)
4088 add_trace("to", NULL, "CH(%lu)", port_id);
4089 if (dir == DIRECTION_IN)
4090 add_trace("from", NULL, "CH(%lu)", port_id);
4094 case MESSAGE_PROCEEDING:
4095 trace_header("PROCEEDING", dir);
4096 if (dir == DIRECTION_OUT)
4097 add_trace("to", NULL, "CH(%lu)", port_id);
4098 if (dir == DIRECTION_IN)
4099 add_trace("from", NULL, "CH(%lu)", port_id);
4103 case MESSAGE_ALERTING:
4104 trace_header("ALERTING", dir);
4105 if (dir == DIRECTION_OUT)
4106 add_trace("to", NULL, "CH(%lu)", port_id);
4107 if (dir == DIRECTION_IN)
4108 add_trace("from", NULL, "CH(%lu)", port_id);
4112 case MESSAGE_CONNECT:
4113 trace_header("CONNECT", dir);
4114 if (dir == DIRECTION_OUT)
4115 add_trace("to", NULL, "CH(%lu)", port_id);
4116 if (dir == DIRECTION_IN)
4117 add_trace("from", NULL, "CH(%lu)", port_id);
4118 if (param->connectinfo.extension[0])
4119 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4120 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4121 switch(param->connectinfo.present)
4123 case INFO_PRESENT_RESTRICTED:
4124 add_trace("connect id", "present", "restricted");
4126 case INFO_PRESENT_ALLOWED:
4127 add_trace("connect id", "present", "allowed");
4130 add_trace("connect id", "present", "not available");
4135 case MESSAGE_DISCONNECT:
4136 case MESSAGE_RELEASE:
4137 if (message_type == MESSAGE_DISCONNECT)
4138 trace_header("DISCONNECT", dir);
4140 trace_header("RELEASE", dir);
4141 if (dir == DIRECTION_OUT)
4142 add_trace("to", NULL, "CH(%lu)", port_id);
4143 if (dir == DIRECTION_IN)
4144 add_trace("from", NULL, "CH(%lu)", port_id);
4145 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4146 switch(param->disconnectinfo.location)
4149 add_trace("cause", "location", "0-User");
4151 case LOCATION_PRIVATE_LOCAL:
4152 add_trace("cause", "location", "1-Local-PBX");
4154 case LOCATION_PUBLIC_LOCAL:
4155 add_trace("cause", "location", "2-Local-Exchange");
4157 case LOCATION_TRANSIT:
4158 add_trace("cause", "location", "3-Transit");
4160 case LOCATION_PUBLIC_REMOTE:
4161 add_trace("cause", "location", "4-Remote-Exchange");
4163 case LOCATION_PRIVATE_REMOTE:
4164 add_trace("cause", "location", "5-Remote-PBX");
4166 case LOCATION_INTERNATIONAL:
4167 add_trace("cause", "location", "7-International-Exchange");
4169 case LOCATION_BEYOND:
4170 add_trace("cause", "location", "10-Beyond-Interworking");
4173 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4178 case MESSAGE_NOTIFY:
4179 switch(param->notifyinfo.notify)
4185 logtext = "USER_SUSPENDED";
4188 logtext = "BEARER_SERVICE_CHANGED";
4191 logtext = "USER_RESUMED";
4194 logtext = "CONFERENCE_ESTABLISHED";
4197 logtext = "CONFERENCE_DISCONNECTED";
4200 logtext = "OTHER_PARTY_ADDED";
4203 logtext = "ISOLATED";
4206 logtext = "REATTACHED";
4209 logtext = "OTHER_PARTY_ISOLATED";
4212 logtext = "OTHER_PARTY_REATTACHED";
4215 logtext = "OTHER_PARTY_SPLIT";
4218 logtext = "OTHER_PARTY_DISCONNECTED";
4221 logtext = "CONFERENCE_FLOATING";
4224 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4227 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4230 logtext = "CALL_IS_A_WAITING_CALL";
4233 logtext = "DIVERSION_ACTIVATED";
4236 logtext = "RESERVED_CT_1";
4239 logtext = "RESERVED_CT_2";
4242 logtext = "REVERSE_CHARGING";
4245 logtext = "REMOTE_HOLD";
4248 logtext = "REMOTE_RETRIEVAL";
4251 logtext = "CALL_IS_DIVERTING";
4254 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4258 trace_header("NOTIFY", dir);
4259 if (dir == DIRECTION_OUT)
4260 add_trace("to", NULL, "CH(%lu)", port_id);
4261 if (dir == DIRECTION_IN)
4262 add_trace("from", NULL, "CH(%lu)", port_id);
4263 if (param->notifyinfo.notify)
4264 add_trace("indicator", NULL, "%s", logtext);
4265 if (param->notifyinfo.id[0])
4267 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4268 switch(param->notifyinfo.present)
4270 case INFO_PRESENT_RESTRICTED:
4271 add_trace("redir'on", "present", "restricted");
4273 case INFO_PRESENT_ALLOWED:
4274 add_trace("redir'on", "present", "allowed");
4277 add_trace("redir'on", "present", "not available");
4280 if (param->notifyinfo.display[0])
4281 add_trace("display", NULL, "%s", param->notifyinfo.display);
4285 case MESSAGE_INFORMATION:
4286 trace_header("INFORMATION", dir);
4287 if (dir == DIRECTION_OUT)
4288 add_trace("to", NULL, "CH(%lu)", port_id);
4289 if (dir == DIRECTION_IN)
4290 add_trace("from", NULL, "CH(%lu)", port_id);
4291 add_trace("dialing", NULL, "%s", param->information.id);
4295 case MESSAGE_FACILITY:
4296 trace_header("FACILITY", dir);
4297 if (dir == DIRECTION_OUT)
4298 add_trace("to", NULL, "CH(%lu)", port_id);
4299 if (dir == DIRECTION_IN)
4300 add_trace("from", NULL, "CH(%lu)", port_id);
4305 trace_header("TONE", dir);
4306 if (dir == DIRECTION_OUT)
4307 add_trace("to", NULL, "CH(%lu)", port_id);
4308 if (dir == DIRECTION_IN)
4309 add_trace("from", NULL, "CH(%lu)", port_id);
4310 if (param->tone.name[0])
4312 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4313 add_trace("name", NULL, "%s", param->tone.name);
4315 add_trace("off", NULL, NULL);
4319 case MESSAGE_SUSPEND:
4320 case MESSAGE_RESUME:
4321 if (message_type == MESSAGE_SUSPEND)
4322 trace_header("SUSPEND", dir);
4324 trace_header("RESUME", dir);
4325 if (dir == DIRECTION_OUT)
4326 add_trace("to", NULL, "CH(%lu)", port_id);
4327 if (dir == DIRECTION_IN)
4328 add_trace("from", NULL, "CH(%lu)", port_id);
4329 if (param->parkinfo.len)
4330 add_trace("length", NULL, "%d", param->parkinfo.len);
4335 case MESSAGE_BCHANNEL:
4336 trace_header("BCHANNEL", dir);
4337 switch(param->bchannel.type)
4339 case BCHANNEL_REQUEST:
4340 add_trace("type", NULL, "request");
4342 case BCHANNEL_ASSIGN:
4343 add_trace("type", NULL, "assign");
4345 case BCHANNEL_ASSIGN_ACK:
4346 add_trace("type", NULL, "assign_ack");
4348 case BCHANNEL_REMOVE:
4349 add_trace("type", NULL, "remove");
4351 case BCHANNEL_REMOVE_ACK:
4352 add_trace("type", NULL, "remove_ack");
4355 if (param->bchannel.addr)
4356 add_trace("address", NULL, "%x", param->bchannel.addr);
4362 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4366 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, char *display)
4368 struct lcr_msg *message;
4372 if (!portlist->port_id)
4375 if (!e_connectedmode)
4377 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4378 message->param.disconnectinfo.cause = cause;
4379 message->param.disconnectinfo.location = location;
4381 SCPY(message->param.disconnectinfo.display, display);
4383 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4386 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4388 SCPY(message->param.notifyinfo.display, display);
4390 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4392 message_put(message);
4393 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);