1 /*****************************************************************************\
3 ** Linux Call Router **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** The EndpointAppPBX implements PBX4Linux **
10 \*****************************************************************************/
15 class EndpointAppPBX *apppbx_first = NULL;
17 int action_timeout(struct lcr_timer *timer, void *instance, int index);
18 int match_timeout(struct lcr_timer *timer, void *instance, int index);
19 int redial_timeout(struct lcr_timer *timer, void *instance, int index);
20 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index);
21 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index);
22 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index);
23 int password_timeout(struct lcr_timer *timer, void *instance, int index);
24 int callback_timeout(struct lcr_timer *timer, void *instance, int index);
27 * EndpointAppPBX constructor
29 EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin)
31 class EndpointAppPBX **apppointer;
33 memset(&e_crypt_handler, 0, sizeof(e_crypt_handler));
34 add_timer(&e_crypt_handler, crypt_handler, this, 0);
35 memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh));
36 add_timer(&e_vbox_refresh, vbox_refresh, this, 0);
37 memset(&e_action_timeout, 0, sizeof(e_action_timeout));
38 add_timer(&e_action_timeout, action_timeout, this, 0);
39 memset(&e_match_timeout, 0, sizeof(e_match_timeout));
40 add_timer(&e_match_timeout, match_timeout, this, 0);
41 memset(&e_redial_timeout, 0, sizeof(e_redial_timeout));
42 add_timer(&e_redial_timeout, redial_timeout, this, 0);
43 memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout));
44 add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0);
45 memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout));
46 add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0);
47 memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout));
48 add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0);
49 memset(&e_callback_timeout, 0, sizeof(e_callback_timeout));
50 add_timer(&e_callback_timeout, callback_timeout, this, 0);
51 memset(&e_password_timeout, 0, sizeof(e_password_timeout));
52 add_timer(&e_password_timeout, password_timeout, this, 0);
55 /* add application to chain */
57 apppointer = &apppbx_first;
59 apppointer = &((*apppointer)->next);
63 memset(&e_ext, 0, sizeof(struct extension));
64 // *************** NOTE: also change value in read_extension() **************
65 e_ext.rights = 4; /* international */
66 e_ext.rx_gain = e_ext.tx_gain = 0;
67 e_state = EPOINT_STATE_IDLE;
68 e_ext.number[0] = '\0';
69 e_extension_interface[0] = '\0';
70 memset(&e_callerinfo, 0, sizeof(struct caller_info));
71 memset(&e_dialinginfo, 0, sizeof(struct dialing_info));
72 memset(&e_connectinfo, 0, sizeof(struct connect_info));
73 memset(&e_redirinfo, 0, sizeof(struct redir_info));
74 memset(&e_capainfo, 0, sizeof(struct capa_info));
77 e_ruleset = ruleset_main;
79 e_rule = e_ruleset->rule_first;
82 e_match_to_action = NULL;
84 e_extdialing = e_dialinginfo.id;
88 // e_join_tone[0] = e_hold_tone[0] = '\0';
89 e_join_pattern /*= e_hold_pattern*/ = 0;
91 e_adminid = 0; // will be set, if call was initiated via admin socket
94 e_cbdialing[0] = '\0';
97 memset(&e_callbackinfo, 0, sizeof(struct caller_info));
103 e_multipoint_cause = 0;
104 e_multipoint_location = 0;
105 e_dialing_queue[0] = '\0';
107 e_crypt_state = CM_ST_NULL;
108 e_crypt_keyengine_busy = 0;
109 e_crypt_info[0] = '\0';
112 e_tx_state = NOTIFY_STATE_ACTIVE;
113 e_rx_state = NOTIFY_STATE_ACTIVE;
114 e_join_cause = e_join_location = 0;
115 /*********************************
116 *********************************
117 ********* ATTENTION *************
118 *********************************
119 *********************************/
120 /* if you add new values, that must be initialized, also check if they must
121 * be initialized when doing callback
127 * EpointAppPBX destructor
129 EndpointAppPBX::~EndpointAppPBX(void)
131 class EndpointAppPBX *temp, **tempp;
133 del_timer(&e_crypt_handler);
134 del_timer(&e_vbox_refresh);
135 del_timer(&e_action_timeout);
136 del_timer(&e_match_timeout);
137 del_timer(&e_redial_timeout);
138 del_timer(&e_powerdial_timeout);
139 del_timer(&e_cfnr_timeout);
140 del_timer(&e_cfnr_call_timeout);
141 del_timer(&e_callback_timeout);
142 del_timer(&e_password_timeout);
146 tempp = &apppbx_first;
155 FATAL("Endpoint not in endpoint's list.\n");
162 * trace header for application
164 void EndpointAppPBX::trace_header(const char *name, int direction)
168 char msgtext[sizeof(_trace.name)];
172 /* init trace with given values */
175 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
179 ea_endpoint->ep_serial,
186 /* set new endpoint state
188 void EndpointAppPBX::new_state(int state)
191 if (e_state != state) {
192 trace_header("NEW STATE", DIRECTION_NONE);
193 add_trace("state", "old", "%s", state_name[e_state]);
194 add_trace("state", "new", "%s", state_name[state]);
202 /* release join and port (as specified)
204 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force)
206 struct port_list *portlist;
207 struct lcr_msg *message;
210 /* message to test call */
211 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
213 /* if a release is pending */
214 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
215 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
216 if (ea_endpoint->ep_join_id) {
217 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
218 message->param.disconnectinfo.cause = joincause;
219 message->param.disconnectinfo.location = joinlocation;
220 message_put(message);
221 ea_endpoint->ep_join_id = 0;
225 if (release != RELEASE_PORT_JOINONLY) {
227 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
232 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
233 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
234 while((portlist = ea_endpoint->ep_portlist)) {
235 if (portlist->port_id) {
236 SPRINT(cause, "cause_%02x", portcause);
237 set_tone(portlist, cause);
238 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
239 message->param.disconnectinfo.cause = portcause;
240 message->param.disconnectinfo.location = portlocation;
241 message->param.disconnectinfo.force = force; // set, if port should release imediately
242 message_put(message);
243 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
245 ea_endpoint->free_portlist(portlist);
248 /* if callback is enabled, call back with the given caller id */
249 if (e_callback_timeout.active) {
250 /* reset some stuff */
251 new_state(EPOINT_STATE_IDLE);
252 memset(&e_connectinfo, 0, sizeof(struct connect_info));
253 memset(&e_redirinfo, 0, sizeof(struct redir_info));
254 e_start = e_stop = 0;
255 e_ruleset = ruleset_main;
257 e_rule = e_ruleset->rule_first;
259 unsched_timer(&e_action_timeout);
260 unsched_timer(&e_match_timeout);
261 unsched_timer(&e_cfnr_timeout);
262 unsched_timer(&e_cfnr_call_timeout);
263 e_match_to_action = NULL;
265 e_extdialing = e_dialinginfo.id;
271 e_multipoint_cause = 0;
272 e_multipoint_location = 0;
273 e_dialing_queue[0] = '\0';
275 e_crypt_state = CM_ST_NULL;
276 e_crypt_keyengine_busy = 0;
277 e_crypt_info[0] = '\0';
281 e_tx_state = NOTIFY_STATE_ACTIVE;
282 e_rx_state = NOTIFY_STATE_ACTIVE;
283 e_join_cause = e_join_location = 0;
285 /* the caller info of the callback user */
286 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
287 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
288 /* create dialing by callerinfo */
289 if (e_ext.number[0] && e_extension_interface[0]) {
290 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
291 /* create callback to the current terminal */
292 SCPY(e_dialinginfo.id, e_ext.number);
293 SCPY(e_dialinginfo.interfaces, e_extension_interface);
294 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
295 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
298 SCPY(e_dialinginfo.id, e_cbto);
300 /* numberrize caller id and use it to dial to the callback */
301 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
303 e_dialinginfo.itype = INFO_ITYPE_ISDN;
304 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
305 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
310 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
311 if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */
312 trigger_work(&ea_endpoint->ep_delete);
318 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
319 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
321 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");
323 /* caller id is not restricted, so we do nothing */
324 if (*present != INFO_PRESENT_RESTRICTED)
327 /* only extensions are restricted */
331 /* if we enabled anonymouse ignore */
332 if (ext->anon_ignore)
335 /* else we remove the caller id */
339 *ntype = INFO_NTYPE_UNKNOWN;
341 // *screen = INFO_SCREEN_USER;
342 // maybe we should not make voip address anonymous
345 // maybe it's no fraud to present extension id
347 // extension[0] = '\0';
352 /* used display message to display callerid as available */
353 char *EndpointAppPBX::apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name)
355 static char display[81];
358 const char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
360 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");
369 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
371 /* internal extension's caller id */
372 if (extension[0] && e_ext.display_int) {
374 SCAT(display, extension);
377 if (itype == INFO_ITYPE_VBOX)
378 SCAT(display, "(vbox)");
380 SCAT(display, "(int)");
383 /* external caller id */
384 if (!extension[0] && e_ext.display_ext) {
387 if (present == INFO_PRESENT_RESTRICTED)
388 SCAT(display, "anonymous");
390 SCAT(display, "unknown");
397 /* display if callerid is anonymouse but available due anon-ignore */
398 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED) {
400 SCAT(display, "unknown");
403 SCAT(display, " anon");
406 /* display if callerid is anonymouse but available due anon-ignore */
407 if (e_ext.display_fake && screen==INFO_SCREEN_USER && ntype!=INFO_NTYPE_NOTPRESENT) {
410 if (present == INFO_PRESENT_RESTRICTED)
411 SCAT(display, "anonymous");
413 SCAT(display, "unknown");
418 SCAT(display, " fake");
422 if (name[0] && e_ext.display_name) {
423 if (!display[0] && cid[0])
434 * uses the current state to notify activity
436 void EndpointAppPBX::notify_active(void)
438 struct port_list *portlist = ea_endpoint->ep_portlist;
439 struct lcr_msg *message;
443 case NOTIFY_STATE_ACTIVE:
444 /* we are already active, so we don't do anything */
447 case NOTIFY_STATE_SUSPEND:
448 notify = INFO_NOTIFY_USER_RESUMED;
450 set_tone(portlist, NULL);
451 portlist = portlist->next;
453 portlist = ea_endpoint->ep_portlist;
456 case NOTIFY_STATE_HOLD:
457 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
459 set_tone(portlist, NULL);
460 portlist = portlist->next;
462 portlist = ea_endpoint->ep_portlist;
465 case NOTIFY_STATE_CONFERENCE:
466 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
468 set_tone(portlist, NULL);
469 portlist = portlist->next;
471 portlist = ea_endpoint->ep_portlist;
475 PERROR("unknown e_tx_state = %d\n", e_tx_state);
480 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
481 message->param.notifyinfo.notify = notify;
482 message_put(message);
483 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
484 portlist = portlist->next;
490 * keypad functions during call. one example to use this is to put a call on hold or start a conference
492 void EndpointAppPBX::keypad_function(char digit)
495 /* we must be in a call, in order to send messages to the call */
496 if (e_ext.number[0] == '\0') {
497 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
502 /* join conference */
504 if (ea_endpoint->ep_join_id == 0) {
505 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
508 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
514 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
518 /* crypt key-exchange */
520 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
526 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
531 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
536 /* set tone pattern for port */
537 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
539 struct lcr_msg *message;
544 /* store for suspended processes */
548 if (e_join_pattern /* pattern are provided */
549 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
550 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
551 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
552 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
553 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
554 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
555 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
556 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
557 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
558 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
559 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
560 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
565 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
566 SCPY(message->param.tone.dir, e_ext.tones_dir);
567 SCPY(message->param.tone.name, tone);
568 message_put(message);
569 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
571 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
578 * hunts an mISDNport that is available for an outgoing call
579 * if no ifname was given, any interface that is not an extension
582 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
584 struct interface *interface;
585 struct interface_port *ifport, *ifport_start;
586 struct select_channel *selchannel;
587 struct mISDNport *mISDNport;
589 int there_is_an_external = 0;
591 interface = interface_first;
593 /* first find the given interface or, if not given, one with no extension */
596 if (!there_is_an_external && !(ifname && ifname[0])) {
597 trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
598 add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
604 /* check for given interface */
605 if (ifname && ifname[0]) {
606 if (!strcasecmp(interface->name, ifname)) {
607 /* found explicit interface */
608 trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
609 add_trace("interface", NULL, "%s", ifname);
615 if (interface->external) {
616 there_is_an_external = 1;
617 /* found non extension */
618 trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
619 add_trace("interface", NULL, "%s", interface->name);
625 interface = interface->next;
629 /* see if interface has ports */
630 if (!interface->ifport) {
632 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
633 add_trace("interface", NULL, "%s", interface->name);
635 interface = interface->next;
639 /* select port by algorithm */
640 ifport_start = interface->ifport;
642 if (interface->hunt == HUNT_ROUNDROBIN) {
643 while(ifport_start->next && index<interface->hunt_next) {
644 ifport_start = ifport_start->next;
647 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
648 add_trace("port", NULL, "%d", ifport_start->portnum);
649 add_trace("position", NULL, "%d", index);
654 ifport = ifport_start;
657 /* see if port is available */
658 if (!ifport->mISDNport) {
659 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
660 add_trace("port", NULL, "%d", ifport->portnum);
661 add_trace("position", NULL, "%d", index);
665 mISDNport = ifport->mISDNport;
667 /* see if port is administratively blocked */
669 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
670 add_trace("port", NULL, "%d", ifport->portnum);
671 add_trace("position", NULL, "%d", index);
676 /* see if link is up on PTP*/
677 if (mISDNport->l2hold && mISDNport->l2link<1) {
678 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
679 add_trace("port", NULL, "%d", ifport->portnum);
680 add_trace("position", NULL, "%d", index);
685 /* check for channel form selection list */
688 if (mISDNport->ss5) {
690 port = ss5_hunt_line(mISDNport);
692 *channel = port->p_m_b_channel;
693 trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
694 add_trace("port", NULL, "%d", ifport->portnum);
695 add_trace("position", NULL, "%d", index);
696 add_trace("channel", NULL, "%d", *channel);
702 selchannel = ifport->out_channel;
704 switch(selchannel->channel) {
705 case CHANNEL_FREE: /* free channel */
706 if (mISDNport->b_reserved >= mISDNport->b_num)
707 break; /* all channel in use or reserverd */
710 while(i < mISDNport->b_num) {
711 if (mISDNport->b_port[i] == NULL) {
712 *channel = i+1+(i>=15);
713 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
714 add_trace("port", NULL, "%d", ifport->portnum);
715 add_trace("position", NULL, "%d", index);
716 add_trace("channel", NULL, "%d", *channel);
724 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
725 add_trace("port", NULL, "%d", ifport->portnum);
726 add_trace("position", NULL, "%d", index);
730 case CHANNEL_ANY: /* don't ask for channel */
731 if (mISDNport->b_reserved >= mISDNport->b_num) {
732 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
733 add_trace("port", NULL, "%d", ifport->portnum);
734 add_trace("position", NULL, "%d", index);
735 add_trace("total", NULL, "%d", mISDNport->b_num);
736 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
738 break; /* all channel in use or reserverd */
740 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
741 add_trace("port", NULL, "%d", ifport->portnum);
742 add_trace("position", NULL, "%d", index);
744 *channel = CHANNEL_ANY;
747 case CHANNEL_NO: /* call waiting */
748 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
749 add_trace("port", NULL, "%d", ifport->portnum);
750 add_trace("position", NULL, "%d", index);
752 *channel = CHANNEL_NO;
756 if (selchannel->channel<1 || selchannel->channel==16) {
757 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
758 add_trace("port", NULL, "%d", ifport->portnum);
759 add_trace("position", NULL, "%d", index);
760 add_trace("channel", NULL, "%d", selchannel->channel);
762 break; /* invalid channels */
764 i = selchannel->channel-1-(selchannel->channel>=17);
765 if (i >= mISDNport->b_num) {
766 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
767 add_trace("port", NULL, "%d", ifport->portnum);
768 add_trace("position", NULL, "%d", index);
769 add_trace("channel", NULL, "%d", selchannel->channel);
770 add_trace("channels", NULL, "%d", mISDNport->b_num);
772 break; /* channel not in port */
774 if (mISDNport->b_port[i] == NULL) {
775 *channel = selchannel->channel;
776 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
777 add_trace("port", NULL, "%d", ifport->portnum);
778 add_trace("position", NULL, "%d", index);
779 add_trace("channel", NULL, "%d", *channel);
786 break; /* found channel */
787 selchannel = selchannel->next;
791 /* if channel was found, return mISDNport and channel */
793 /* setting next port to start next time */
794 if (interface->hunt == HUNT_ROUNDROBIN) {
798 interface->hunt_next = index;
804 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
805 add_trace("port", NULL, "%d", ifport->portnum);
806 add_trace("position", NULL, "%d", index);
810 /* go next port, until all ports are checked */
812 ifport = ifport->next;
815 ifport = interface->ifport;
817 if (ifport != ifport_start)
821 interface = interface->next;
825 return(NULL); /* no port found */
828 /* outgoing setup to port(s)
829 * ports will be created and a setup is sent if everything is ok. otherwhise
830 * the endpoint is destroyed.
832 void EndpointAppPBX::out_setup(int cfnr)
834 struct dialing_info dialinginfo;
836 struct port_list *portlist;
837 struct lcr_msg *message;
839 int cause = CAUSE_RESSOURCEUNAVAIL;
842 struct mISDNport *mISDNport;
845 class EndpointAppPBX *atemp;
846 // char allowed_ports[256];
848 char ifname[sizeof(e_ext.interfaces)],
850 struct port_settings port_settings;
853 int mode = B_MODE_TRANSPARENT;
854 struct admin_list *admin;
856 /* set bchannel mode */
857 mode = e_capainfo.source_mode;
859 /* create settings for creating port */
860 memset(&port_settings, 0, sizeof(port_settings));
862 SCPY(port_settings.tones_dir, e_ext.tones_dir);
864 SCPY(port_settings.tones_dir, options.tones_dir);
865 port_settings.no_seconds = e_ext.no_seconds;
867 /* 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 */
869 /* check what dialinginfo.itype we got */
870 switch(e_dialinginfo.itype) {
871 /* *********************** call to extension or vbox */
872 case INFO_ITYPE_ISDN_EXTENSION:
873 /* check if we deny incoming calls when we use an extension */
874 if (e_ext.noknocking) {
875 atemp = apppbx_first;
878 if (!strcmp(atemp->e_ext.number, e_ext.number))
883 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
884 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
885 return; /* must exit here */
888 /* FALL THROUGH !!!! */
889 case INFO_ITYPE_VBOX:
890 /* get dialed extension's info */
891 // SCPY(exten, e_dialinginfo.id);
892 // if (strchr(exten, ','))
893 // *strchr(exten, ',') = '\0';
894 // if (!read_extension(&e_ext, exten))
895 if (!read_extension(&e_ext, e_dialinginfo.id)) {
896 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
897 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
898 return; /* must exit here */
900 e_dialinginfo.sending_complete = 1;
902 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
903 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
908 /* string from unconditional call forward (cfu) */
911 /* present to forwarded party */
912 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
913 e_callerinfo.present = INFO_PRESENT_ALLOWED;
915 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
919 /* string from busy call forward (cfb) */
922 class EndpointAppPBX *checkapp = apppbx_first;
924 if (checkapp != this) { /* any other endpoint except our own */
925 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
926 /* present to forwarded party */
927 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) */
941 /* when cfnr is done, out_setup() will setup the call */
943 /* present to forwarded party */
944 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
945 e_callerinfo.present = INFO_PRESENT_ALLOWED;
949 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
950 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
951 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
952 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);
956 /* call to all internal interfaces */
957 p = e_ext.interfaces;
958 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
961 while(*p!=',' && *p!='\0')
966 /* found interface */
967 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
968 /* hunt for mISDNport and create Port */
969 mISDNport = hunt_port(ifname, &channel);
971 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
972 add_trace("interface", NULL, "%s", ifname);
976 /* creating INTERNAL port */
977 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
980 port = ss5_hunt_line(mISDNport);
984 if (mISDNport->gsm_bs)
985 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
989 if (mISDNport->gsm_ms)
990 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
994 if (mISDNport->ifport->interface->sip)
995 port = new Psip(PORT_TYPE_SIP_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, mISDNport->ifport->interface);
998 if (mISDNport->ifport->remote) {
1001 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1003 admin = admin->next;
1006 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1007 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1011 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1013 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1015 FATAL("Failed to create Port instance\n");
1016 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
1017 memset(&dialinginfo, 0, sizeof(dialinginfo));
1018 SCPY(dialinginfo.id, e_dialinginfo.id);
1019 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1020 dialinginfo.ntype = e_dialinginfo.ntype;
1021 /* create port_list relation */
1022 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1024 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1026 goto check_anycall_intern;
1028 /* directory.list */
1029 if (e_callerinfo.id[0] && e_ext.display_name) {
1030 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1032 SCPY(e_callerinfo.name, dirname);
1034 // dss1 = (class Pdss1 *)port;
1036 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1037 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1038 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1039 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1040 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1041 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1042 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1043 //terminal if (e_dialinginfo.id)
1044 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1045 /* handle restricted caller ids */
1046 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);
1047 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1048 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);
1049 /* display callerid if desired for extension */
1050 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));
1051 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1052 /* use cnip, if enabld */
1053 // if (!e_ext.centrex)
1054 // message->param.setup.callerinfo.name[0] = '\0';
1055 /* screen clip if prefix is required */
1056 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1057 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1058 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1059 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1061 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1062 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1063 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1064 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1066 /* use internal caller id */
1067 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1068 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1069 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1070 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1072 message_put(message);
1073 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1077 /* string from parallel call forward (cfp) */
1080 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1081 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1082 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1086 vbox_only: /* entry point for answering machine only */
1087 cfu_only: /* entry point for cfu */
1088 cfb_only: /* entry point for cfb */
1089 cfnr_only: /* entry point for cfnr */
1090 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1094 /* only if vbox should be dialed, and terminal is given */
1095 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1096 /* go to the end of p */
1099 /* answering vbox call */
1100 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1102 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1103 FATAL("No memory for VBOX Port instance\n");
1104 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1105 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1108 while(*p!=',' && *p!='\0')
1113 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1114 /* hunt for mISDNport and create Port */
1115 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1117 /* creating EXTERNAL port*/
1118 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1121 port = ss5_hunt_line(mISDNport);
1124 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1126 FATAL("No memory for Port instance\n");
1127 earlyb = mISDNport->earlyb;
1130 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1131 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1136 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1137 goto check_anycall_intern;
1139 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1140 memset(&dialinginfo, 0, sizeof(dialinginfo));
1141 SCPY(dialinginfo.id, cfp);
1142 dialinginfo.itype = INFO_ITYPE_ISDN;
1143 dialinginfo.ntype = e_dialinginfo.ntype;
1144 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1146 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1148 goto check_anycall_intern;
1150 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1151 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1152 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1153 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1154 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1155 /* if clip is hidden */
1156 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1157 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1158 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1159 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1160 message->param.setup.callerinfo.present = e_ext.callerid_present;
1161 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1163 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1164 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1165 //terminal if (e_dialinginfo.id)
1166 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1167 /* handle restricted caller ids */
1168 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);
1169 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1170 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);
1171 /* display callerid if desired for extension */
1172 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));
1173 message_put(message);
1174 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1178 check_anycall_intern:
1179 /* now we have all ports created */
1181 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1183 if (!ea_endpoint->ep_join_id)
1185 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1186 return; /* must exit here */
1190 /* *********************** external call */
1192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1193 /* call to extenal interfaces */
1194 if (e_dialinginfo.keypad[0])
1195 p = e_dialinginfo.keypad;
1197 p = e_dialinginfo.id;
1200 while(*p!=',' && *p!='\0')
1201 SCCAT(number, *p++);
1205 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");
1206 /* hunt for mISDNport and create Port */
1207 /* hunt for mISDNport and create Port */
1208 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1210 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1211 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1213 goto check_anycall_extern;
1215 /* creating EXTERNAL port*/
1216 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1219 port = ss5_hunt_line(mISDNport);
1223 if (mISDNport->gsm_bs)
1224 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1228 if (mISDNport->gsm_ms)
1229 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1233 if (mISDNport->ifport->interface->sip)
1234 port = new Psip(PORT_TYPE_SIP_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, mISDNport->ifport->interface);
1237 if (mISDNport->ifport->remote) {
1238 admin = admin_first;
1240 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1242 admin = admin->next;
1245 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1246 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1250 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1252 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1254 FATAL("No memory for Port instance\n");
1255 earlyb = mISDNport->earlyb;
1256 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1257 memset(&dialinginfo, 0, sizeof(dialinginfo));
1258 if (e_dialinginfo.keypad[0])
1259 SCPY(dialinginfo.keypad, number);
1261 SCPY(dialinginfo.id, number);
1262 dialinginfo.itype = INFO_ITYPE_ISDN;
1263 dialinginfo.ntype = e_dialinginfo.ntype;
1264 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1265 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1267 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1269 goto check_anycall_extern;
1271 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1272 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1273 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1274 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1275 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1276 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1277 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1278 //terminal if (e_dialinginfo.id)
1279 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1280 /* handle restricted caller ids */
1281 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);
1282 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1283 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);
1284 /* display callerid if desired for extension */
1285 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));
1286 message_put(message);
1287 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1291 check_anycall_extern:
1292 /* now we have all ports created */
1294 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1296 if (!ea_endpoint->ep_join_id)
1298 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1299 return; /* must exit here */
1306 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1308 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1310 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1313 unsched_timer(&ea->e_redial_timeout);
1314 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1315 ea->e_multipoint_cause = 0;
1316 ea->e_multipoint_location = 0;
1317 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1318 ea->e_join_pattern = 0;
1319 ea->process_dialing(1);
1320 /* we must exit, because our endpoint might be gone */
1325 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1327 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1329 if (!ea->e_action) {
1330 unsched_timer(&ea->e_redial_timeout);
1331 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1332 ea->process_dialing(0);
1333 /* we must exit, because our endpoint might be gone */
1339 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1341 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1343 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1345 ea->new_state(EPOINT_STATE_OUT_SETUP);
1346 /* call special setup routine */
1352 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1354 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1356 /* leave power dialing on */
1357 ea->e_powerdial_on = 1;
1358 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1361 ea->e_ruleset = ruleset_main;
1363 ea->e_rule = ea->e_ruleset->rule_first;
1364 ea->e_action = NULL;
1365 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1366 ea->process_dialing(0);
1371 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1373 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1374 struct port_list *portlist;
1375 struct lcr_msg *message;
1377 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1379 /* release all ports */
1380 while((portlist = ea->ea_endpoint->ep_portlist)) {
1381 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1382 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1383 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1384 message_put(message);
1385 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1386 ea->ea_endpoint->free_portlist(portlist);
1389 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1390 message->param.audiopath = 0;
1391 message_put(message);
1392 /* indicate no patterns */
1393 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1394 message_put(message);
1395 /* set setup state, since we have no response from the new join */
1396 ea->new_state(EPOINT_STATE_OUT_SETUP);
1401 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1403 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1405 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr);
1411 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1413 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1415 if (ea->e_state == EPOINT_STATE_IDLE) {
1416 /* epoint is idle, check callback */
1417 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1418 ea->new_state(EPOINT_STATE_OUT_SETUP);
1425 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1427 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1429 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1430 struct port_list *portlist;
1432 ea->e_ruleset = ruleset_main;
1434 ea->e_rule = ea->e_ruleset->rule_first;
1435 ea->e_action = NULL;
1436 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1437 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1439 ea->e_connectedmode = 0;
1441 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1442 portlist = ea->ea_endpoint->ep_portlist;
1444 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1445 ea->set_tone(portlist, "cause_10");
1452 /* doing a hookflash */
1453 void EndpointAppPBX::hookflash(void)
1458 /* be sure that we are active */
1460 e_tx_state = NOTIFY_STATE_ACTIVE;
1462 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1464 if (ea_endpoint->ep_use > 1) {
1465 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1468 /* dialtone after pressing the hash key */
1469 process_hangup(e_join_cause, e_join_location);
1470 e_multipoint_cause = 0;
1471 e_multipoint_location = 0;
1472 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1474 port->set_echotest(0);
1476 if (ea_endpoint->ep_join_id) {
1477 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1479 e_ruleset = ruleset_main;
1481 e_rule = e_ruleset->rule_first;
1483 new_state(EPOINT_STATE_IN_OVERLAP);
1484 e_connectedmode = 1;
1485 SCPY(e_dialinginfo.id, e_ext.prefix);
1486 e_extdialing = e_dialinginfo.id;
1488 if (e_dialinginfo.id[0]) {
1489 set_tone(ea_endpoint->ep_portlist, "dialing");
1492 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1500 /* messages from port
1502 /* port MESSAGE_SETUP */
1503 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1505 struct lcr_msg *message;
1507 int writeext; /* flags need to write extension after modification */
1509 struct interface *interface;
1511 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1513 portlist->port_type = param->setup.port_type;
1514 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1515 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1516 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1517 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1519 /* convert (inter-)national number type */
1520 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1521 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1523 // e_dtmf = param->setup.dtmf;
1524 /* screen incoming caller id */
1525 interface = interface_first;
1527 if (!strcmp(e_callerinfo.interface, interface->name)) {
1530 interface = interface->next;
1533 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1534 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1537 /* process extension */
1538 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1539 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1540 /* port makes call from extension */
1541 SCPY(e_callerinfo.extension, e_callerinfo.id);
1542 SCPY(e_ext.number, e_callerinfo.extension);
1543 SCPY(e_extension_interface, e_callerinfo.interface);
1545 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1548 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1549 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1551 /* get extension's info about caller */
1552 if (!read_extension(&e_ext, e_ext.number)) {
1553 /* extension doesn't exist */
1554 trace_header("EXTENSION (not created)", DIRECTION_IN);
1555 add_trace("extension", NULL, "%s", e_ext.number);
1557 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1558 new_state(EPOINT_STATE_OUT_DISCONNECT);
1559 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1560 e_ext.number[0] = '\0'; /* no terminal */
1565 /* put prefix (next) in front of e_dialinginfo.id */
1566 if (e_ext.next[0]) {
1567 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1568 SCPY(e_dialinginfo.id, buffer);
1569 e_ext.next[0] = '\0';
1571 } else if (e_ext.prefix[0]) {
1572 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1573 SCPY(e_dialinginfo.id, buffer);
1576 /* screen caller id by extension's config */
1577 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1579 SCPY(e_callerinfo.name, e_ext.name);
1580 /* use caller id (or if exist: id_next_call) for this call */
1581 if (e_ext.id_next_call_present >= 0) {
1582 SCPY(e_callerinfo.id, e_ext.id_next_call);
1583 /* if we restrict the pesentation */
1584 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1585 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1586 else e_callerinfo.present = e_ext.id_next_call_present;
1587 e_callerinfo.ntype = e_ext.id_next_call_type;
1588 e_ext.id_next_call_present = -1;
1591 SCPY(e_callerinfo.id, e_ext.callerid);
1592 /* if we restrict the pesentation */
1593 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1594 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1595 else e_callerinfo.present = e_ext.callerid_present;
1596 e_callerinfo.ntype = e_ext.callerid_type;
1598 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1600 /* extension is written */
1602 write_extension(&e_ext, e_ext.number);
1604 /* set volume of rx and tx */
1605 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1606 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1607 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1608 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1609 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1610 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1611 message_put(message);
1614 /* start recording if enabled */
1615 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1616 /* check if we are a terminal */
1617 if (e_ext.number[0] == '\0')
1618 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1620 port = find_port_id(portlist->port_id);
1622 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1626 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1627 /* no terminal identification */
1628 e_ext.number[0] = '\0';
1629 e_extension_interface[0] = '\0';
1630 memset(&e_ext, 0, sizeof(e_ext));
1631 e_ext.rights = 4; /* right to dial internat */
1635 e_ruleset = ruleset_main;
1637 e_rule = e_ruleset->rule_first;
1639 e_extdialing = e_dialinginfo.id;
1640 new_state(EPOINT_STATE_IN_SETUP);
1641 if (e_dialinginfo.id[0]) {
1642 set_tone(portlist, "dialing");
1644 if (e_ext.number[0])
1645 set_tone(portlist, "dialpbx");
1647 set_tone(portlist, "dialtone");
1650 if (e_state == EPOINT_STATE_IN_SETUP) {
1651 /* request MORE info, if not already at higher state */
1652 new_state(EPOINT_STATE_IN_OVERLAP);
1653 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1654 message_put(message);
1655 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1659 /* port MESSAGE_INFORMATION */
1660 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1662 struct lcr_msg *message;
1664 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1666 /* ignore information message without digit information */
1667 if (!param->information.id[0])
1672 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1674 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1679 /* if vbox_play is done, the information are just used as they come */
1681 if (e_action->index == ACTION_VBOX_PLAY) {
1682 /* concat dialing string */
1683 SCAT(e_dialinginfo.id, param->information.id);
1688 /* keypad when disconnect but in connected mode */
1689 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1690 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1691 /* processing keypad function */
1692 if (param->information.id[0] == '0') {
1698 /* keypad when connected */
1699 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1700 if (e_enablekeypad) {
1701 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1702 memcpy(&message->param, param, sizeof(union parameter));
1703 message_put(message);
1707 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1708 /* processing keypad function */
1709 if (param->information.id[0] == '0') {
1712 if (param->information.id[0])
1713 keypad_function(param->information.id[0]);
1715 if (e_ext.number[0])
1716 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1718 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1723 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1724 if (e_ext.number[0])
1725 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1727 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1731 if (!param->information.id[0])
1733 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1734 set_tone(portlist, "dialing");
1737 if (e_action->index==ACTION_OUTDIAL
1738 || e_action->index==ACTION_EXTERNAL
1739 || e_action->index==ACTION_REMOTE) {
1741 set_tone(portlist, "dialing");
1742 else if (!e_extdialing[0])
1743 set_tone(portlist, "dialing");
1745 /* concat dialing string */
1746 SCAT(e_dialinginfo.id, param->information.id);
1750 /* port MESSAGE_DTMF */
1751 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1754 struct lcr_msg *message;
1758 /* only if dtmf detection is enabled */
1760 trace_header("DTMF (disabled)", DIRECTION_IN);
1764 trace_header("DTMF", DIRECTION_IN);
1765 add_trace("digit", NULL, "%c", param->dtmf);
1769 NOTE: vbox is now handled due to overlap state
1770 /* if vbox_play is done, the dtmf digits are just used as they come */
1772 if (e_action->index == ACTION_VBOX_PLAY) {
1773 /* concat dialing string */
1774 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1775 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1776 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1779 /* continue to process *X# sequences */
1783 /* check for *X# sequence */
1784 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1785 if (e_enablekeypad) {
1786 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1787 memcpy(&message->param, param, sizeof(union parameter));
1788 message_put(message);
1791 if (e_dtmf_time+3 < now) {
1792 /* the last digit was too far in the past to be a sequence */
1793 if (param->dtmf == '*')
1794 /* only start is allowed in the sequence */
1799 /* we have a sequence of digits, see what we got */
1800 if (param->dtmf == '*')
1802 else if (param->dtmf>='0' && param->dtmf<='9') {
1803 /* we need to have a star before we receive the digit of the sequence */
1804 if (e_dtmf_last == '*')
1805 e_dtmf_last = param->dtmf;
1806 } else if (param->dtmf == '#') {
1808 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1809 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1810 if (e_dtmf_last == '0') {
1814 /* processing keypad function */
1816 keypad_function(e_dtmf_last);
1822 /* set last time of dtmf */
1827 /* check for ## hookflash during dialing */
1829 if (e_action->index==ACTION_PASSWORD
1830 || e_action->index==ACTION_PASSWORD_WRITE)
1832 if (param->dtmf=='#') { /* current digit is '#' */
1833 if (e_state==EPOINT_STATE_IN_DISCONNECT
1834 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1848 /* dialing using dtmf digit */
1849 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1850 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1851 set_tone(portlist, "dialing");
1853 /* concat dialing string */
1854 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1855 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1856 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1862 /* port MESSAGE_CRYPT */
1863 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1865 /* send crypt response to cryptman */
1866 if (param->crypt.type == CR_MESSAGE_IND)
1867 cryptman_msg2man(param->crypt.data, param->crypt.len);
1869 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1872 /* port MESSAGE_OVERLAP */
1873 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1875 struct lcr_msg *message;
1877 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1879 /* signal to call tool */
1880 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1882 if (e_dialing_queue[0] && portlist) {
1883 /* send what we have not dialed yet, because we had no setup complete */
1884 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1885 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1886 SCPY(message->param.information.id, e_dialing_queue);
1887 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1888 message_put(message);
1889 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1890 e_dialing_queue[0] = '\0';
1892 /* check if pattern is available */
1893 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1894 /* indicate patterns */
1895 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1896 message_put(message);
1898 /* connect audio, if not already */
1899 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1900 message->param.audiopath = 1;
1901 message_put(message);
1903 /* indicate no patterns */
1904 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1905 message_put(message);
1907 /* disconnect audio, if not already */
1908 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1909 message->param.audiopath = 0;
1910 message_put(message);
1912 new_state(EPOINT_STATE_OUT_OVERLAP);
1913 /* if we are in a join */
1914 if (ea_endpoint->ep_join_id) {
1915 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1916 memcpy(&message->param, param, sizeof(union parameter));
1917 message_put(message);
1921 /* port MESSAGE_PROCEEDING */
1922 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1924 struct lcr_msg *message;
1926 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1928 /* signal to call tool */
1929 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1931 e_state = EPOINT_STATE_OUT_PROCEEDING;
1932 /* check if pattern is availatle */
1933 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1934 /* indicate patterns */
1935 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1936 message_put(message);
1938 /* connect audio, if not already */
1939 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1940 message->param.audiopath = 1;
1941 message_put(message);
1943 /* indicate no patterns */
1944 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1945 message_put(message);
1947 /* disconnect audio, if not already */
1948 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1949 message->param.audiopath = 0;
1950 message_put(message);
1952 /* if we are in a call */
1953 if (ea_endpoint->ep_join_id) {
1954 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1955 memcpy(&message->param, param, sizeof(union parameter));
1956 message_put(message);
1960 /* port MESSAGE_ALERTING */
1961 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1963 struct lcr_msg *message;
1965 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1967 /* signal to call tool */
1968 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1971 // set_tone(portlist, "hold");
1973 new_state(EPOINT_STATE_OUT_ALERTING);
1974 /* check if pattern is available */
1975 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1976 /* indicate patterns */
1977 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1978 message_put(message);
1980 /* connect audio, if not already */
1981 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1982 message->param.audiopath = 1;
1983 message_put(message);
1985 /* indicate no patterns */
1986 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1987 message_put(message);
1989 /* disconnect audio, if not already */
1990 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1991 message->param.audiopath = 0;
1992 message_put(message);
1994 /* if we are in a call */
1995 if (ea_endpoint->ep_join_id) {
1996 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1997 memcpy(&message->param, param, sizeof(union parameter));
1998 message_put(message);
2002 /* port MESSAGE_CONNECT */
2003 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
2005 struct lcr_msg *message;
2007 unsigned int port_id = portlist->port_id;
2008 struct port_list *tportlist;
2010 struct interface *interface;
2013 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2015 /* signal to call tool */
2016 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
2018 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
2019 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2020 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
2021 tportlist = ea_endpoint->ep_portlist;
2022 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2023 tportlist = tportlist->next;
2024 if (tportlist->port_id == port_id)
2025 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2026 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2027 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
2028 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2029 message_put(message);
2030 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
2031 ea_endpoint->free_portlist(tportlist);
2033 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2038 /* screen incoming connected id */
2039 interface = interface_first;
2041 if (!strcmp(e_connectinfo.interface, interface->name)) {
2044 interface = interface->next;
2047 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
2049 /* screen connected name */
2051 SCPY(e_connectinfo.name, e_ext.name);
2053 /* add internal id to colp */
2054 SCPY(e_connectinfo.extension, e_ext.number);
2056 /* we store the connected port number */
2057 SCPY(e_extension_interface, e_connectinfo.interface);
2059 /* for internal and am calls, we get the extension's id */
2060 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
2061 SCPY(e_connectinfo.id, e_ext.callerid);
2062 SCPY(e_connectinfo.extension, e_ext.number);
2063 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2064 e_connectinfo.ntype = e_ext.callerid_type;
2065 e_connectinfo.present = e_ext.callerid_present;
2067 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2068 e_connectinfo.itype = INFO_ITYPE_VBOX;
2069 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2072 new_state(EPOINT_STATE_CONNECT);
2074 /* set volume of rx and tx */
2075 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2076 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2077 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2078 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2079 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2080 message_put(message);
2083 unsched_timer(&e_cfnr_timeout);
2084 unsched_timer(&e_cfnr_call_timeout);
2085 if (e_ext.number[0])
2086 e_dtmf = 1; /* allow dtmf */
2089 /* other calls with no caller id (or not available for the extension) and force colp */
2090 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2091 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2092 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
2093 /* external extension answered */
2094 port = find_port_id(portlist->port_id);
2096 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2097 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2102 /* send connect to join */
2103 if (ea_endpoint->ep_join_id) {
2104 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2105 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2106 message_put(message);
2108 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2109 message->param.audiopath = 1;
2110 message_put(message);
2111 } else if (!e_adminid) {
2113 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2114 SCPY(e_ext.number, e_cbcaller);
2115 new_state(EPOINT_STATE_IN_OVERLAP);
2116 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2118 /* get extension's info about terminal */
2119 if (!read_extension(&e_ext, e_ext.number)) {
2120 /* extension doesn't exist */
2121 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2122 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2123 new_state(EPOINT_STATE_OUT_DISCONNECT);
2124 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2128 /* put prefix in front of e_cbdialing */
2129 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2130 SCPY(e_dialinginfo.id, buffer);
2131 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2132 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2134 /* use caller id (or if exist: id_next_call) for this call */
2135 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2136 SCPY(e_callerinfo.extension, e_ext.number);
2137 if (e_ext.id_next_call_present >= 0) {
2138 SCPY(e_callerinfo.id, e_ext.id_next_call);
2139 e_callerinfo.present = e_ext.id_next_call_present;
2140 e_callerinfo.ntype = e_ext.id_next_call_type;
2141 e_ext.id_next_call_present = -1;
2142 /* extension is written */
2143 write_extension(&e_ext, e_ext.number);
2145 SCPY(e_callerinfo.id, e_ext.callerid);
2146 e_callerinfo.present = e_ext.callerid_present;
2147 e_callerinfo.ntype = e_ext.callerid_type;
2149 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2151 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2154 /* check if caller id is NOT authenticated */
2155 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2156 /* make call state to enter password */
2157 new_state(EPOINT_STATE_IN_OVERLAP);
2158 e_action = &action_password_write;
2159 unsched_timer(&e_match_timeout);
2160 e_match_to_action = NULL;
2161 e_dialinginfo.id[0] = '\0';
2162 e_extdialing = strchr(e_dialinginfo.id, '\0');
2163 schedule_timer(&e_password_timeout, 20, 0);
2166 /* incoming call (callback) */
2167 e_ruleset = ruleset_main;
2169 e_rule = e_ruleset->rule_first;
2171 e_extdialing = e_dialinginfo.id;
2172 if (e_dialinginfo.id[0]) {
2173 set_tone(portlist, "dialing");
2176 set_tone(portlist, "dialpbx");
2179 } else { /* testcall */
2180 set_tone(portlist, "hold");
2183 /* start recording if enabled, not when answering machine answers */
2184 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)) {
2185 /* check if we are a terminal */
2186 if (e_ext.number[0] == '\0')
2187 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2189 port = find_port_id(portlist->port_id);
2191 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2196 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2197 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2199 struct lcr_msg *message;
2201 unsigned int port_id = portlist->port_id;
2205 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2207 /* signal to call tool */
2208 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2210 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2211 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2212 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2217 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);
2218 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2219 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2221 /* check if we have more than one portlist relation and we just ignore the disconnect */
2222 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2223 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2224 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) {
2233 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2234 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2235 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2236 message_put(message);
2237 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2239 ea_endpoint->free_portlist(portlist);
2240 return; /* one relation removed */
2242 if (e_state == EPOINT_STATE_CONNECT) {
2243 /* use cause from port after connect */
2244 cause = param->disconnectinfo.cause;
2245 location = param->disconnectinfo.location;
2247 /* use multipoint cause if no connect yet */
2248 if (e_multipoint_cause) {
2249 cause = e_multipoint_cause;
2250 location = e_multipoint_location;
2252 cause = CAUSE_NOUSER;
2253 location = LOCATION_PRIVATE_LOCAL;
2257 unsched_timer(&e_cfnr_timeout);
2258 unsched_timer(&e_cfnr_call_timeout);
2260 /* process hangup */
2261 process_hangup(e_join_cause, e_join_location);
2262 e_multipoint_cause = 0;
2263 e_multipoint_location = 0;
2265 if (message_type == MESSAGE_DISCONNECT) {
2266 /* tone to disconnected end */
2267 SPRINT(buffer, "cause_%02x", cause);
2268 if (ea_endpoint->ep_portlist)
2269 set_tone(ea_endpoint->ep_portlist, buffer);
2271 new_state(EPOINT_STATE_IN_DISCONNECT);
2274 if (ea_endpoint->ep_join_id) {
2275 int haspatterns = 0;
2276 /* check if pattern is available */
2277 if (ea_endpoint->ep_portlist)
2278 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2279 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
2280 && message_type != MESSAGE_RELEASE) // if we release, we are done
2283 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2284 /* indicate patterns */
2285 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2286 message_put(message);
2287 /* connect audio, if not already */
2288 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2289 message->param.audiopath = 1;
2290 message_put(message);
2291 /* send disconnect */
2292 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2293 memcpy(&message->param, param, sizeof(union parameter));
2294 message_put(message);
2295 /* disable encryption if disconnected */
2296 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2298 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2301 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2304 if (message_type == MESSAGE_RELEASE)
2305 ea_endpoint->free_portlist(portlist);
2306 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2307 return; /* must exit here */
2310 /* port MESSAGE_TIMEOUT */
2311 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2315 trace_header("TIMEOUT", DIRECTION_IN);
2316 message_type = MESSAGE_DISCONNECT;
2317 switch (param->state) {
2318 case PORT_STATE_OUT_SETUP:
2319 case PORT_STATE_OUT_OVERLAP:
2320 add_trace("state", NULL, "outgoing setup/dialing");
2322 /* no user responding */
2323 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2324 return; /* must exit here */
2326 case PORT_STATE_IN_SETUP:
2327 case PORT_STATE_IN_OVERLAP:
2328 add_trace("state", NULL, "incoming setup/dialing");
2329 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2330 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2333 case PORT_STATE_OUT_PROCEEDING:
2334 add_trace("state", NULL, "outgoing proceeding");
2336 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2337 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2338 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2339 return; /* must exit here */
2341 case PORT_STATE_IN_PROCEEDING:
2342 add_trace("state", NULL, "incoming proceeding");
2343 param->disconnectinfo.cause = CAUSE_NOUSER;
2344 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2347 case PORT_STATE_OUT_ALERTING:
2348 add_trace("state", NULL, "outgoing alerting");
2350 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2351 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2352 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2353 return; /* must exit here */
2355 case PORT_STATE_CONNECT:
2356 add_trace("state", NULL, "connect");
2358 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2359 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2360 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2361 return; /* must exit here */
2363 case PORT_STATE_IN_ALERTING:
2364 add_trace("state", NULL, "incoming alerting");
2365 param->disconnectinfo.cause = CAUSE_NOANSWER;
2366 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2369 case PORT_STATE_IN_DISCONNECT:
2370 case PORT_STATE_OUT_DISCONNECT:
2371 add_trace("state", NULL, "disconnect");
2373 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2374 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2375 return; /* must exit here */
2378 param->disconnectinfo.cause = 31; /* normal unspecified */
2379 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2382 /* release call, disconnect isdn */
2384 new_state(EPOINT_STATE_OUT_DISCONNECT);
2385 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2386 SCPY(e_tone, cause);
2388 set_tone(portlist, cause);
2389 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2390 portlist = portlist->next;
2392 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2395 /* port MESSAGE_NOTIFY */
2396 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2398 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2400 struct lcr_msg *message;
2401 const char *logtext = "";
2404 /* signal to call tool */
2405 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);
2406 if (param->notifyinfo.notify) {
2407 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2410 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2411 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2412 case INFO_NOTIFY_REMOTE_HOLD:
2413 case INFO_NOTIFY_USER_SUSPENDED:
2414 /* tell call about it */
2415 if (ea_endpoint->ep_join_id) {
2416 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2417 message->param.audiopath = 0;
2418 message_put(message);
2422 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2423 case INFO_NOTIFY_USER_RESUMED:
2424 /* set volume of rx and tx */
2425 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2426 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2428 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2429 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2430 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2431 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2432 message_put(message);
2434 /* set current tone */
2436 set_tone(portlist, e_tone);
2437 /* tell call about it */
2438 if (ea_endpoint->ep_join_id) {
2439 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2440 message->param.audiopath = 1;
2441 message_put(message);
2446 /* get name of notify */
2447 switch(param->notifyinfo.notify) {
2452 logtext = "USER_SUSPENDED";
2455 logtext = "BEARER_SERVICE_CHANGED";
2458 logtext = "USER_RESUMED";
2461 logtext = "CONFERENCE_ESTABLISHED";
2464 logtext = "CONFERENCE_DISCONNECTED";
2467 logtext = "OTHER_PARTY_ADDED";
2470 logtext = "ISOLATED";
2473 logtext = "REATTACHED";
2476 logtext = "OTHER_PARTY_ISOLATED";
2479 logtext = "OTHER_PARTY_REATTACHED";
2482 logtext = "OTHER_PARTY_SPLIT";
2485 logtext = "OTHER_PARTY_DISCONNECTED";
2488 logtext = "CONFERENCE_FLOATING";
2491 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2494 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2497 logtext = "CALL_IS_A_WAITING_CALL";
2500 logtext = "DIVERSION_ACTIVATED";
2503 logtext = "RESERVED_CT_1";
2506 logtext = "RESERVED_CT_2";
2509 logtext = "REVERSE_CHARGING";
2512 logtext = "REMOTE_HOLD";
2515 logtext = "REMOTE_RETRIEVAL";
2518 logtext = "CALL_IS_DIVERTING";
2521 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2526 /* notify call if available */
2527 if (ea_endpoint->ep_join_id) {
2528 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2529 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2530 message_put(message);
2535 /* port MESSAGE_PROGRESS */
2536 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2538 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2540 struct lcr_msg *message;
2542 /* signal to call tool */
2543 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2545 /* send progress to call if available */
2546 if (ea_endpoint->ep_join_id) {
2547 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2548 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2549 message_put(message);
2554 /* port MESSAGE_FACILITY */
2555 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2557 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2559 struct lcr_msg *message;
2561 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2562 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2563 message_put(message);
2566 /* port MESSAGE_SUSPEND */
2567 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2568 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2570 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2572 /* epoint is now parked */
2573 ea_endpoint->ep_park = 1;
2574 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2575 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2577 /* remove port relation */
2578 ea_endpoint->free_portlist(portlist);
2581 /* port MESSAGE_RESUME */
2582 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2583 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2585 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2587 /* epoint is now resumed */
2588 ea_endpoint->ep_park = 0;
2592 /* port MESSAGE_ENABLEKEYPAD */
2593 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2595 struct lcr_msg *message;
2597 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2599 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2600 memcpy(&message->param, param, sizeof(union parameter));
2601 message_put(message);
2605 /* port sends message to the endpoint
2607 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2609 struct port_list *portlist;
2611 portlist = ea_endpoint->ep_portlist;
2613 if (port_id == portlist->port_id)
2615 portlist = portlist->next;
2618 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);
2622 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2623 switch(message_type) {
2624 case MESSAGE_DATA: /* data from port */
2625 /* check if there is a call */
2626 if (!ea_endpoint->ep_join_id)
2628 /* continue if only one portlist */
2629 if (ea_endpoint->ep_portlist->next != NULL)
2631 /* forward message */
2632 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2635 case MESSAGE_TONE_EOF: /* tone is end of file */
2636 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2638 if (e_action->index == ACTION_VBOX_PLAY) {
2641 if (e_action->index == ACTION_EFI) {
2647 case MESSAGE_TONE_COUNTER: /* counter info received */
2648 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);
2650 if (e_action->index == ACTION_VBOX_PLAY) {
2651 e_vbox_counter = param->counter.current;
2652 if (param->counter.max >= 0)
2653 e_vbox_counter_max = param->counter.max;
2657 /* PORT sends SETUP message */
2659 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);
2660 if (e_state!=EPOINT_STATE_IDLE) {
2661 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2664 port_setup(portlist, message_type, param);
2667 /* PORT sends INFORMATION message */
2668 case MESSAGE_INFORMATION: /* additional digits received */
2669 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);
2670 port_information(portlist, message_type, param);
2673 /* PORT sends FACILITY message */
2674 case MESSAGE_FACILITY:
2675 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2676 port_facility(portlist, message_type, param);
2679 /* PORT sends DTMF message */
2680 case MESSAGE_DTMF: /* dtmf digits received */
2681 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);
2682 port_dtmf(portlist, message_type, param);
2685 /* PORT sends CRYPT message */
2686 case MESSAGE_CRYPT: /* crypt response received */
2687 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2688 port_crypt(portlist, message_type, param);
2691 /* PORT sends MORE message */
2692 case MESSAGE_OVERLAP:
2693 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);
2694 if (e_state != EPOINT_STATE_OUT_SETUP) {
2695 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);
2698 port_overlap(portlist, message_type, param);
2701 /* PORT sends PROCEEDING message */
2702 case MESSAGE_PROCEEDING: /* port is proceeding */
2703 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);
2704 if (e_state!=EPOINT_STATE_OUT_SETUP
2705 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2706 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);
2709 port_proceeding(portlist, message_type, param);
2712 /* PORT sends ALERTING message */
2713 case MESSAGE_ALERTING:
2714 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);
2715 if (e_state!=EPOINT_STATE_OUT_SETUP
2716 && e_state!=EPOINT_STATE_OUT_OVERLAP
2717 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2718 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);
2721 port_alerting(portlist, message_type, param);
2724 /* PORT sends CONNECT message */
2725 case MESSAGE_CONNECT:
2726 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);
2727 if (e_state!=EPOINT_STATE_OUT_SETUP
2728 && e_state!=EPOINT_STATE_OUT_OVERLAP
2729 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2730 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2731 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2734 port_connect(portlist, message_type, param);
2737 /* PORT sends DISCONNECT message */
2738 case MESSAGE_DISCONNECT: /* port is disconnected */
2739 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);
2740 port_disconnect_release(portlist, message_type, param);
2743 /* PORT sends a RELEASE message */
2744 case MESSAGE_RELEASE: /* port releases */
2745 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);
2746 /* portlist is release at port_disconnect_release, thanx Paul */
2747 port_disconnect_release(portlist, message_type, param);
2750 /* PORT sends a TIMEOUT message */
2751 case MESSAGE_TIMEOUT:
2752 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);
2753 port_timeout(portlist, message_type, param);
2754 break; /* release */
2756 /* PORT sends a NOTIFY message */
2757 case MESSAGE_NOTIFY:
2758 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);
2759 port_notify(portlist, message_type, param);
2762 /* PORT sends a PROGRESS message */
2763 case MESSAGE_PROGRESS:
2764 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received progress.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2765 port_progress(portlist, message_type, param);
2768 /* PORT sends a SUSPEND message */
2769 case MESSAGE_SUSPEND:
2770 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);
2771 port_suspend(portlist, message_type, param);
2772 break; /* suspend */
2774 /* PORT sends a RESUME message */
2775 case MESSAGE_RESUME:
2776 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);
2777 port_resume(portlist, message_type, param);
2781 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2782 /* port assigns bchannel */
2783 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2784 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);
2785 /* only one port is expected to be connected to bchannel */
2786 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2787 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2791 /* PORT requests DTMF */
2792 case MESSAGE_ENABLEKEYPAD:
2793 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') requests DTMF/KEYPAD.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2794 port_enablekeypad(portlist, message_type, param);
2799 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: %d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
2802 /* Note: this endpoint may be destroyed, so we MUST return */
2806 /* messages from join
2808 /* join MESSAGE_CRYPT */
2809 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2811 switch(param->crypt.type) {
2812 /* message from remote port to "crypt manager" */
2813 case CU_ACTK_REQ: /* activate key-exchange */
2814 case CU_ACTS_REQ: /* activate shared key */
2815 case CU_DACT_REQ: /* deactivate */
2816 case CU_INFO_REQ: /* request last info message */
2817 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2820 /* message from "crypt manager" to user */
2821 case CU_ACTK_CONF: /* key-echange done */
2822 case CU_ACTS_CONF: /* shared key done */
2823 case CU_DACT_CONF: /* deactivated */
2824 case CU_DACT_IND: /* deactivated */
2825 case CU_ERROR_IND: /* receive error message */
2826 case CU_INFO_IND: /* receive info message */
2827 case CU_INFO_CONF: /* receive info message */
2828 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2832 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);
2836 /* join MESSAGE_INFORMATION */
2837 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2839 struct lcr_msg *message;
2844 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2845 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2846 message_put(message);
2847 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2848 portlist = portlist->next;
2852 /* join MESSAGE_FACILITY */
2853 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2855 struct lcr_msg *message;
2857 if (!e_ext.facility && e_ext.number[0]) {
2862 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2863 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2864 message_put(message);
2865 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2866 portlist = portlist->next;
2870 /* join MESSAGE_MORE */
2871 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2873 struct lcr_msg *message;
2875 new_state(EPOINT_STATE_IN_OVERLAP);
2878 if (e_join_pattern && e_ext.own_setup) {
2879 /* disconnect audio */
2880 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2881 message->param.audiopath = 0;
2882 message_put(message);
2884 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2885 if (e_dialinginfo.id[0])
2886 set_tone(portlist, "dialing");
2888 set_tone(portlist, "dialtone");
2891 if (e_dialinginfo.id[0]) {
2892 set_tone(portlist, "dialing");
2894 if (e_ext.number[0])
2895 set_tone(portlist, "dialpbx");
2897 set_tone(portlist, "dialtone");
2901 /* join MESSAGE_PROCEEDING */
2902 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2904 struct lcr_msg *message;
2906 new_state(EPOINT_STATE_IN_PROCEEDING);
2908 /* own proceeding tone */
2909 if (e_join_pattern) {
2910 /* connect / disconnect audio */
2911 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2912 if (e_ext.own_proceeding)
2913 message->param.audiopath = 0;
2915 message->param.audiopath = 1;
2916 message_put(message);
2918 // UCPY(e_join_tone, "proceeding");
2920 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2921 message_put(message);
2922 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2924 set_tone(portlist, "proceeding");
2927 /* join MESSAGE_ALERTING */
2928 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2930 struct lcr_msg *message;
2932 new_state(EPOINT_STATE_IN_ALERTING);
2934 /* own alerting tone */
2935 if (e_join_pattern) {
2936 /* connect / disconnect audio */
2937 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2938 if (e_ext.own_alerting)
2939 message->param.audiopath = 0;
2941 message->param.audiopath = 1;
2942 message_put(message);
2945 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2946 message_put(message);
2947 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2949 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2950 set_tone(portlist, "ringing");
2953 if (e_ext.number[0])
2954 set_tone(portlist, "ringpbx");
2956 set_tone(portlist, "ringing");
2958 if (e_ext.number[0])
2959 e_dtmf = 1; /* allow dtmf */
2962 /* join MESSAGE_CONNECT */
2963 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2965 struct lcr_msg *message;
2968 new_state(EPOINT_STATE_CONNECT);
2969 // UCPY(e_join_tone, "");
2971 if (e_ext.number[0])
2972 e_dtmf = 1; /* allow dtmf */
2975 unsched_timer(&e_powerdial_timeout);
2976 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2978 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2979 memcpy(&message->param, param, sizeof(union parameter));
2981 /* screen clip if prefix is required */
2982 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2983 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2984 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2985 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2988 /* use internal caller id */
2989 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2990 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2991 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2994 /* handle restricted caller ids */
2995 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);
2996 /* display callerid if desired for extension */
2997 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));
2999 /* use conp, if enabld */
3000 // if (!e_ext.centrex)
3001 // message->param.connectinfo.name[0] = '\0';
3004 message_put(message);
3005 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3007 set_tone(portlist, NULL);
3009 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3010 message->param.audiopath = 1;
3011 message_put(message);
3016 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3017 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3020 struct lcr_msg *message;
3021 struct port_list *portlist = NULL;
3025 /* be sure that we are active */
3027 e_tx_state = NOTIFY_STATE_ACTIVE;
3029 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
3030 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
3031 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
3033 /* set time for power dialing */
3034 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
3037 /* set redial tone */
3038 if (ea_endpoint->ep_portlist) {
3041 set_tone(ea_endpoint->ep_portlist, "redial");
3042 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);
3043 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3044 if (e_state==EPOINT_STATE_IN_OVERLAP) {
3045 new_state(EPOINT_STATE_IN_PROCEEDING);
3046 if (ea_endpoint->ep_portlist) {
3047 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3048 message_put(message);
3049 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3051 /* caused the error, that the first knock sound was not there */
3052 /* set_tone(portlist, "proceeding"); */
3054 /* send display of powerdialing */
3055 if (e_ext.display_dialing) {
3056 portlist = ea_endpoint->ep_portlist;
3058 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3060 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3062 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3063 message_put(message);
3064 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3065 portlist = portlist->next;
3075 if ((e_state!=EPOINT_STATE_CONNECT
3076 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3077 && e_state!=EPOINT_STATE_IN_OVERLAP
3078 && e_state!=EPOINT_STATE_IN_PROCEEDING
3079 && e_state!=EPOINT_STATE_IN_ALERTING)
3080 || !ea_endpoint->ep_portlist) { /* or no port */
3081 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3082 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3083 return; /* must exit here */
3086 if (!e_join_cause) {
3087 e_join_cause = param->disconnectinfo.cause;
3088 e_join_location = param->disconnectinfo.location;
3091 /* on release we need the audio again! */
3092 if (message_type == MESSAGE_RELEASE) {
3094 ea_endpoint->ep_join_id = 0;
3096 /* disconnect and select tone */
3097 new_state(EPOINT_STATE_OUT_DISCONNECT);
3098 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3099 /* if own_cause, we must release the join */
3100 if (e_ext.own_cause /* own cause */
3101 || !e_join_pattern) { /* no patterns */
3102 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);
3103 if (message_type != MESSAGE_RELEASE)
3104 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3106 } else { /* else we enable audio */
3107 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3108 message->param.audiopath = 1;
3109 message_put(message);
3111 /* send disconnect message */
3112 SCPY(e_tone, cause);
3113 portlist = ea_endpoint->ep_portlist;
3115 set_tone(portlist, cause);
3116 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3117 portlist = portlist->next;
3121 /* join MESSAGE_SETUP */
3122 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3124 struct lcr_msg *message;
3125 // struct interface *interface;
3127 /* if we already in setup state, we just update the dialing with new digits */
3128 if (e_state == EPOINT_STATE_OUT_SETUP
3129 || 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))) {
3133 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);
3134 /* release all ports */
3135 while((portlist = ea_endpoint->ep_portlist)) {
3136 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3137 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3138 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3139 message_put(message);
3140 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3141 ea_endpoint->free_portlist(portlist);
3144 /* disconnect audio */
3145 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3146 message->param.audiopath = 0;
3147 message_put(message);
3149 /* get dialing info */
3150 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3151 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3152 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3153 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3154 new_state(EPOINT_STATE_OUT_OVERLAP);
3157 schedule_timer(&e_redial_timeout, 1, 0);
3160 /* if we have a pending redial, so we just adjust the dialing number */
3161 if (e_redial_timeout.active) {
3162 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);
3163 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3166 if (!ea_endpoint->ep_portlist) {
3167 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3169 if (ea_endpoint->ep_portlist->next) {
3170 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3172 if (e_state == EPOINT_STATE_OUT_SETUP) {
3174 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);
3175 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3178 /* get what we have not dialed yet */
3179 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));
3180 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3181 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3182 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3183 message_put(message);
3184 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3186 /* always store what we have dialed or queued */
3187 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3191 if (e_state != EPOINT_STATE_IDLE) {
3192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3195 /* if an internal extension is dialed, copy that number */
3196 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3197 SCPY(e_ext.number, param->setup.dialinginfo.id);
3198 /* if an internal extension is dialed, get extension's info about caller */
3199 if (e_ext.number[0]) {
3200 if (!read_extension(&e_ext, e_ext.number)) {
3201 e_ext.number[0] = '\0';
3202 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3206 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3207 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3208 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3209 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3211 /* process (voice over) data calls */
3212 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3213 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3214 memset(&e_capainfo, 0, sizeof(e_capainfo));
3215 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3216 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3217 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3220 new_state(EPOINT_STATE_OUT_SETUP);
3221 /* call special setup routine */
3225 /* join MESSAGE_mISDNSIGNAL */
3226 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3228 struct lcr_msg *message;
3231 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3232 memcpy(&message->param, param, sizeof(union parameter));
3233 message_put(message);
3234 portlist = portlist->next;
3238 /* join MESSAGE_NOTIFY */
3239 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3241 struct lcr_msg *message;
3244 if (param->notifyinfo.notify) {
3245 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3246 // /* if notification was generated locally, we turn hold music on/off */
3247 // if (param->notifyinfo.local)
3248 // 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)
3252 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3253 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3255 set_tone(portlist, "");
3256 portlist = portlist->next;
3259 portlist = ea_endpoint->ep_portlist;
3264 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3266 set_tone(portlist, "hold");
3267 portlist = portlist->next;
3269 portlist = ea_endpoint->ep_portlist;
3274 /* save new state */
3275 e_tx_state = new_state;
3278 /* notify port(s) about it */
3280 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3281 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3282 /* handle restricted caller ids */
3283 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3284 /* display callerid if desired for extension */
3285 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));
3286 message_put(message);
3287 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3288 portlist = portlist->next;
3292 /* join MESSAGE_DTMF */
3293 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3295 struct lcr_msg *message;
3298 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3299 memcpy(&message->param, param, sizeof(union parameter));
3300 message_put(message);
3301 portlist = portlist->next;
3305 /* JOIN sends messages to the endpoint
3307 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3309 struct port_list *portlist;
3310 struct lcr_msg *message;
3313 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3317 portlist = ea_endpoint->ep_portlist;
3319 /* send MESSAGE_DATA to port */
3320 if (message_type == MESSAGE_DATA) {
3321 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3322 /* skip if no port relation */
3325 /* skip if more than one port relation */
3328 /* forward audio data to port */
3329 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3334 // 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);
3335 switch(message_type) {
3336 /* JOIN SENDS TONE message */
3338 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);
3339 set_tone(portlist, param->tone.name);
3342 /* JOIN SENDS CRYPT message */
3344 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);
3345 join_crypt(portlist, message_type, param);
3348 /* JOIN sends INFORMATION message */
3349 case MESSAGE_INFORMATION:
3350 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);
3351 join_information(portlist, message_type, param);
3354 /* JOIN sends FACILITY message */
3355 case MESSAGE_FACILITY:
3356 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);
3357 join_facility(portlist, message_type, param);
3360 /* JOIN sends OVERLAP message */
3361 case MESSAGE_OVERLAP:
3362 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received 'more info required'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3363 if (e_state!=EPOINT_STATE_IN_SETUP
3364 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3365 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3368 join_overlap(portlist, message_type, param);
3371 /* JOIN sends PROCEEDING message */
3372 case MESSAGE_PROCEEDING:
3373 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);
3374 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3375 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3378 join_proceeding(portlist, message_type, param);
3381 /* JOIN sends ALERTING message */
3382 case MESSAGE_ALERTING:
3383 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);
3384 if (e_state!=EPOINT_STATE_IN_OVERLAP
3385 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3386 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3389 join_alerting(portlist, message_type, param);
3392 /* JOIN sends CONNECT message */
3393 case MESSAGE_CONNECT:
3394 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);
3395 if (e_state!=EPOINT_STATE_IN_OVERLAP
3396 && e_state!=EPOINT_STATE_IN_PROCEEDING
3397 && e_state!=EPOINT_STATE_IN_ALERTING) {
3398 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3401 join_connect(portlist, message_type, param);
3404 /* JOIN sends DISCONNECT/RELEASE message */
3405 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3406 case MESSAGE_RELEASE: /* JOIN releases */
3407 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);
3408 join_disconnect_release(message_type, param);
3411 /* JOIN sends SETUP message */
3413 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);
3414 join_setup(portlist, message_type, param);
3417 /* JOIN sends special mISDNSIGNAL message */
3418 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3419 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);
3420 join_mISDNsignal(portlist, message_type, param);
3424 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3425 /* JOIN requests bchannel */
3426 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3427 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);
3428 /* only one port is expected to be connected to bchannel */
3435 set_tone(portlist, NULL);
3436 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3437 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3441 /* JOIN has pattern available */
3442 case MESSAGE_PATTERN: /* indicating pattern available */
3443 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);
3444 if (!e_join_pattern) {
3445 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3449 set_tone(portlist, NULL);
3450 portlist = portlist->next;
3452 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3453 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3454 message->param.audiopath = 1;
3455 message_put(message);
3459 /* JOIN has no pattern available */
3460 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3461 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);
3462 if (e_join_pattern) {
3463 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3465 /* disconnect our audio tx and rx */
3466 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3467 message->param.audiopath = 0;
3468 message_put(message);
3473 /* JOIN (dunno at the moment) */
3474 case MESSAGE_REMOTE_AUDIO:
3475 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);
3476 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3477 message->param.audiopath = param->channel;
3478 message_put(message);
3482 /* JOIN sends a notify message */
3483 case MESSAGE_NOTIFY:
3484 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);
3485 join_notify(portlist, message_type, param);
3488 /* JOIN wants keypad / dtmf */
3489 case MESSAGE_ENABLEKEYPAD:
3490 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received keypad enable request.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3493 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3497 /* JOIN sends a DTMF message */
3499 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received dtmf.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3500 join_dtmf(portlist, message_type, param);
3504 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received a wrong message: #%d\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, message_type);
3509 /* pick_join will connect the first incoming call found. the endpoint
3510 * will receivce a MESSAGE_CONNECT.
3512 int match_list(char *list, char *item)
3514 char *end, *next = NULL;
3516 /* no list make matching */
3521 /* eliminate white spaces */
3522 while (*list > '\0' && *list <= ' ')
3528 /* if end of list is reached, we return */
3529 if (list[0] == '\0')
3531 /* if we have more than one entry (left) */
3532 if ((end = strchr(list, ',')))
3535 next = end = strchr(list, '\0');
3536 while (*(end-1) <= ' ')
3538 /* if string part matches item */
3539 if (!strncmp(list, item, end-list))
3545 void EndpointAppPBX::pick_join(char *extensions)
3547 struct lcr_msg *message;
3548 struct port_list *portlist;
3550 class EndpointAppPBX *eapp, *found;
3552 class JoinPBX *joinpbx;
3553 struct join_relation *relation;
3556 /* find an endpoint that is ringing internally or vbox with higher priority */
3559 eapp = apppbx_first;
3561 if (eapp!=this && ea_endpoint->ep_portlist) {
3562 portlist = eapp->ea_endpoint->ep_portlist;
3564 if ((port = find_port_id(portlist->port_id))) {
3565 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3566 if (match_list(extensions, eapp->e_ext.number)) {
3572 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3573 && port->p_state==PORT_STATE_OUT_ALERTING)
3574 if (match_list(extensions, eapp->e_ext.number)) {
3578 portlist = portlist->next;
3586 /* if no endpoint found */
3588 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);
3590 set_tone(ea_endpoint->ep_portlist, "cause_10");
3591 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3592 new_state(EPOINT_STATE_OUT_DISCONNECT);
3597 if (ea_endpoint->ep_join_id) {
3598 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3601 if (!eapp->ea_endpoint->ep_join_id) {
3602 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3605 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3607 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3610 if (join->j_type != JOIN_TYPE_PBX) {
3611 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3614 joinpbx = (class JoinPBX *)join;
3615 relation = joinpbx->j_relation;
3617 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3620 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3621 relation = relation->next;
3623 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3628 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3630 if (options.deb & DEBUG_EPOINT) {
3631 class Join *debug_c = join_first;
3632 class Endpoint *debug_e = epoint_first;
3633 class Port *debug_p = port_first;
3635 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3637 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3639 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3640 debug_c = debug_c->next;
3642 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3644 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3645 debug_e = debug_e->next;
3647 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3649 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3650 debug_p = debug_p->next;
3655 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3656 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3657 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3659 /* connnecting our endpoint */
3660 new_state(EPOINT_STATE_CONNECT);
3661 if (e_ext.number[0])
3663 set_tone(ea_endpoint->ep_portlist, NULL);
3665 /* now we send a release to the ringing endpoint */
3666 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3667 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3668 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3669 message_put(message);
3671 /* we send a connect to the join with our caller id */
3672 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3673 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3674 message->param.connectinfo.present = e_callerinfo.present;
3675 message->param.connectinfo.screen = e_callerinfo.screen;
3676 message->param.connectinfo.itype = e_callerinfo.itype;
3677 message->param.connectinfo.ntype = e_callerinfo.ntype;
3678 message_put(message);
3680 /* we send a connect to our port with the remote callerid */
3681 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3682 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3683 message->param.connectinfo.present = eapp->e_callerinfo.present;
3684 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3685 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3686 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3687 /* handle restricted caller ids */
3688 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);
3689 /* display callerid if desired for extension */
3690 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));
3691 message_put(message);
3693 /* we send a connect to the audio path (not for vbox) */
3694 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3695 message->param.audiopath = 1;
3696 message_put(message);
3698 /* beeing paranoid, we make call update */
3699 trigger_work(&joinpbx->j_updatebridge);
3701 if (options.deb & DEBUG_EPOINT) {
3702 class Join *debug_c = join_first;
3703 class Endpoint *debug_e = epoint_first;
3704 class Port *debug_p = port_first;
3706 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3708 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3710 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3711 debug_c = debug_c->next;
3713 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3715 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3716 debug_e = debug_e->next;
3718 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3720 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3721 debug_p = debug_p->next;
3727 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3729 void EndpointAppPBX::join_join(void)
3731 struct lcr_msg *message;
3732 struct join_relation *our_relation, *other_relation;
3733 struct join_relation **our_relation_pointer, **other_relation_pointer;
3734 class Join *our_join, *other_join;
3735 class JoinPBX *our_joinpbx, *other_joinpbx;
3736 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3737 class Port *our_port, *other_port;
3738 class Pdss1 *our_pdss1, *other_pdss1;
3740 /* are we a candidate to join a join? */
3741 our_join = find_join_id(ea_endpoint->ep_join_id);
3743 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3746 if (our_join->j_type != JOIN_TYPE_PBX) {
3747 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3750 our_joinpbx = (class JoinPBX *)our_join;
3751 if (!ea_endpoint->ep_portlist) {
3752 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3755 if (!e_ext.number[0]) {
3756 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3759 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3761 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3764 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3765 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3768 our_pdss1 = (class Pdss1 *)our_port;
3770 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3771 other_eapp = apppbx_first;
3773 if (other_eapp == this) {
3774 other_eapp = other_eapp->next;
3777 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);
3778 if (other_eapp->e_ext.number[0] /* has terminal */
3779 && other_eapp->ea_endpoint->ep_portlist /* has port */
3780 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3781 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3782 if (other_port) { /* port still exists */
3783 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3784 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3785 other_pdss1 = (class Pdss1 *)other_port;
3786 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);
3787 if (other_pdss1->p_m_hold /* port is on hold */
3788 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3789 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3792 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3795 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3798 other_eapp = other_eapp->next;
3801 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3804 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3806 /* if we have the same join */
3807 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3808 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3811 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3813 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3816 if (other_join->j_type != JOIN_TYPE_PBX) {
3817 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3820 other_joinpbx = (class JoinPBX *)other_join;
3821 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3822 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3826 /* remove relation to endpoint for join on hold */
3827 other_relation = other_joinpbx->j_relation;
3828 other_relation_pointer = &other_joinpbx->j_relation;
3829 while(other_relation) {
3830 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3831 /* detach other endpoint on hold */
3832 *other_relation_pointer = other_relation->next;
3833 FREE(other_relation, sizeof(struct join_relation));
3835 other_relation = *other_relation_pointer;
3836 other_eapp->ea_endpoint->ep_join_id = 0;
3840 /* change join/hold pointer of endpoint to the new join */
3841 temp_epoint = find_epoint_id(other_relation->epoint_id);
3843 if (temp_epoint->ep_join_id == other_join->j_serial)
3844 temp_epoint->ep_join_id = our_join->j_serial;
3847 other_relation_pointer = &other_relation->next;
3848 other_relation = other_relation->next;
3850 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3852 /* join call relations */
3853 our_relation = our_joinpbx->j_relation;
3854 our_relation_pointer = &our_joinpbx->j_relation;
3855 while(our_relation) {
3856 our_relation_pointer = &our_relation->next;
3857 our_relation = our_relation->next;
3859 *our_relation_pointer = other_joinpbx->j_relation;
3860 other_joinpbx->j_relation = NULL;
3861 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3863 /* release endpoint on hold */
3864 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3865 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3866 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3867 message_put(message);
3869 /* if we are not a partyline, we get partyline state from other join */
3870 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3872 /* remove empty join */
3874 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3876 /* mixer must update */
3877 trigger_work(&our_joinpbx->j_updatebridge);
3879 /* we send a retrieve to that endpoint */
3880 // mixer will update the hold-state of the join and send it to the endpoints is changes
3884 /* check if we have an external call
3885 * this is used to check for encryption ability
3887 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3889 struct join_relation *relation;
3891 class JoinPBX *joinpbx;
3892 class Endpoint *epoint;
3894 /* some paranoia check */
3895 if (!ea_endpoint->ep_portlist) {
3896 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3897 *errstr = "No Call";
3900 if (!e_ext.number[0]) {
3901 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3902 *errstr = "No Call";
3906 /* check if we have a join with 2 parties */
3907 join = find_join_id(ea_endpoint->ep_join_id);
3909 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3910 *errstr = "No Call";
3913 if (join->j_type != JOIN_TYPE_PBX) {
3914 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3915 *errstr = "No PBX Call";
3918 joinpbx = (class JoinPBX *)join;
3919 relation = joinpbx->j_relation;
3921 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3922 *errstr = "No Call";
3925 if (!relation->next) {
3926 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3927 *errstr = "No Call";
3930 if (relation->next->next) {
3931 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3932 *errstr = "Err: Conference";
3935 if (relation->epoint_id == ea_endpoint->ep_serial) {
3936 relation = relation->next;
3937 if (relation->epoint_id == ea_endpoint->ep_serial) {
3938 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3939 *errstr = "Software Error";
3944 /* check remote port for external call */
3945 epoint = find_epoint_id(relation->epoint_id);
3947 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3948 *errstr = "No Call";
3951 if (!epoint->ep_portlist) {
3952 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3953 *errstr = "No Call";
3956 *port = find_port_id(epoint->ep_portlist->port_id);
3958 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3959 *errstr = "No Call";
3962 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
3963 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3964 *errstr = "No Ext Call";
3967 if ((*port)->p_state != PORT_STATE_CONNECT) {
3968 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3969 *errstr = "No Ext Connect";
3975 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3977 const char *logtext = "unknown";
3980 switch(message_type) {
3982 trace_header("SETUP", dir);
3983 if (dir == DIRECTION_OUT)
3984 add_trace("to", NULL, "CH(%lu)", port_id);
3985 if (dir == DIRECTION_IN)
3986 add_trace("from", NULL, "CH(%lu)", port_id);
3987 if (param->setup.callerinfo.extension[0])
3988 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3989 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3990 switch(param->setup.callerinfo.present) {
3991 case INFO_PRESENT_RESTRICTED:
3992 add_trace("caller id", "present", "restricted");
3994 case INFO_PRESENT_ALLOWED:
3995 add_trace("caller id", "present", "allowed");
3998 add_trace("caller id", "present", "not available");
4000 if (param->setup.callerinfo.ntype2) {
4001 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4002 switch(param->setup.callerinfo.present) {
4003 case INFO_PRESENT_RESTRICTED:
4004 add_trace("caller id2", "present", "restricted");
4006 case INFO_PRESENT_ALLOWED:
4007 add_trace("caller id2", "present", "allowed");
4010 add_trace("caller id2", "present", "not available");
4013 if (param->setup.redirinfo.id[0]) {
4014 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4015 switch(param->setup.redirinfo.present) {
4016 case INFO_PRESENT_RESTRICTED:
4017 add_trace("redir'ing", "present", "restricted");
4019 case INFO_PRESENT_ALLOWED:
4020 add_trace("redir'ing", "present", "allowed");
4023 add_trace("redir'ing", "present", "not available");
4026 if (param->setup.dialinginfo.id[0])
4027 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4028 if (param->setup.dialinginfo.keypad[0])
4029 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4030 if (param->setup.dialinginfo.display[0])
4031 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4032 if (param->setup.dialinginfo.sending_complete)
4033 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4037 case MESSAGE_OVERLAP:
4038 trace_header("SETUP ACKNOWLEDGE", dir);
4039 if (dir == DIRECTION_OUT)
4040 add_trace("to", NULL, "CH(%lu)", port_id);
4041 if (dir == DIRECTION_IN)
4042 add_trace("from", NULL, "CH(%lu)", port_id);
4046 case MESSAGE_PROCEEDING:
4047 trace_header("PROCEEDING", dir);
4048 if (dir == DIRECTION_OUT)
4049 add_trace("to", NULL, "CH(%lu)", port_id);
4050 if (dir == DIRECTION_IN)
4051 add_trace("from", NULL, "CH(%lu)", port_id);
4055 case MESSAGE_ALERTING:
4056 trace_header("ALERTING", dir);
4057 if (dir == DIRECTION_OUT)
4058 add_trace("to", NULL, "CH(%lu)", port_id);
4059 if (dir == DIRECTION_IN)
4060 add_trace("from", NULL, "CH(%lu)", port_id);
4064 case MESSAGE_CONNECT:
4065 trace_header("CONNECT", dir);
4066 if (dir == DIRECTION_OUT)
4067 add_trace("to", NULL, "CH(%lu)", port_id);
4068 if (dir == DIRECTION_IN)
4069 add_trace("from", NULL, "CH(%lu)", port_id);
4070 if (param->connectinfo.extension[0])
4071 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4072 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4073 switch(param->connectinfo.present) {
4074 case INFO_PRESENT_RESTRICTED:
4075 add_trace("connect id", "present", "restricted");
4077 case INFO_PRESENT_ALLOWED:
4078 add_trace("connect id", "present", "allowed");
4081 add_trace("connect id", "present", "not available");
4083 if (param->connectinfo.display[0])
4084 add_trace("display", NULL, "%s", param->connectinfo.display);
4088 case MESSAGE_DISCONNECT:
4089 case MESSAGE_RELEASE:
4090 if (message_type == MESSAGE_DISCONNECT)
4091 trace_header("DISCONNECT", dir);
4093 trace_header("RELEASE", dir);
4094 if (dir == DIRECTION_OUT)
4095 add_trace("to", NULL, "CH(%lu)", port_id);
4096 if (dir == DIRECTION_IN)
4097 add_trace("from", NULL, "CH(%lu)", port_id);
4098 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4099 switch(param->disconnectinfo.location) {
4101 add_trace("cause", "location", "0-User");
4103 case LOCATION_PRIVATE_LOCAL:
4104 add_trace("cause", "location", "1-Local-PBX");
4106 case LOCATION_PUBLIC_LOCAL:
4107 add_trace("cause", "location", "2-Local-Exchange");
4109 case LOCATION_TRANSIT:
4110 add_trace("cause", "location", "3-Transit");
4112 case LOCATION_PUBLIC_REMOTE:
4113 add_trace("cause", "location", "4-Remote-Exchange");
4115 case LOCATION_PRIVATE_REMOTE:
4116 add_trace("cause", "location", "5-Remote-PBX");
4118 case LOCATION_INTERNATIONAL:
4119 add_trace("cause", "location", "7-International-Exchange");
4121 case LOCATION_BEYOND:
4122 add_trace("cause", "location", "10-Beyond-Interworking");
4125 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4127 if (param->disconnectinfo.display[0])
4128 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4132 case MESSAGE_NOTIFY:
4133 switch(param->notifyinfo.notify) {
4138 logtext = "USER_SUSPENDED";
4141 logtext = "BEARER_SERVICE_CHANGED";
4144 logtext = "USER_RESUMED";
4147 logtext = "CONFERENCE_ESTABLISHED";
4150 logtext = "CONFERENCE_DISCONNECTED";
4153 logtext = "OTHER_PARTY_ADDED";
4156 logtext = "ISOLATED";
4159 logtext = "REATTACHED";
4162 logtext = "OTHER_PARTY_ISOLATED";
4165 logtext = "OTHER_PARTY_REATTACHED";
4168 logtext = "OTHER_PARTY_SPLIT";
4171 logtext = "OTHER_PARTY_DISCONNECTED";
4174 logtext = "CONFERENCE_FLOATING";
4177 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4180 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4183 logtext = "CALL_IS_A_WAITING_CALL";
4186 logtext = "DIVERSION_ACTIVATED";
4189 logtext = "RESERVED_CT_1";
4192 logtext = "RESERVED_CT_2";
4195 logtext = "REVERSE_CHARGING";
4198 logtext = "REMOTE_HOLD";
4201 logtext = "REMOTE_RETRIEVAL";
4204 logtext = "CALL_IS_DIVERTING";
4207 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4211 trace_header("NOTIFY", dir);
4212 if (dir == DIRECTION_OUT)
4213 add_trace("to", NULL, "CH(%lu)", port_id);
4214 if (dir == DIRECTION_IN)
4215 add_trace("from", NULL, "CH(%lu)", port_id);
4216 if (param->notifyinfo.notify)
4217 add_trace("indicator", NULL, "%s", logtext);
4218 if (param->notifyinfo.id[0]) {
4219 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4220 switch(param->notifyinfo.present) {
4221 case INFO_PRESENT_RESTRICTED:
4222 add_trace("redir'on", "present", "restricted");
4224 case INFO_PRESENT_ALLOWED:
4225 add_trace("redir'on", "present", "allowed");
4228 add_trace("redir'on", "present", "not available");
4231 if (param->notifyinfo.display[0])
4232 add_trace("display", NULL, "%s", param->notifyinfo.display);
4236 case MESSAGE_PROGRESS:
4237 switch(param->progressinfo.progress) {
4239 logtext = "Call is not end to end ISDN";
4242 logtext = "Destination address is non-ISDN";
4245 logtext = "Origination address is non-ISDN";
4248 logtext = "Call has returned to the ISDN";
4251 logtext = "In-band info or pattern available";
4254 SPRINT(buffer, "%d", param->progressinfo.progress);
4258 trace_header("PROGRESS", 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 add_trace("indicator", NULL, "%s", logtext);
4264 switch(param->progressinfo.location) {
4266 add_trace("cause", "location", "0-User");
4268 case LOCATION_PRIVATE_LOCAL:
4269 add_trace("cause", "location", "1-Local-PBX");
4271 case LOCATION_PUBLIC_LOCAL:
4272 add_trace("cause", "location", "2-Local-Exchange");
4274 case LOCATION_TRANSIT:
4275 add_trace("cause", "location", "3-Transit");
4277 case LOCATION_PUBLIC_REMOTE:
4278 add_trace("cause", "location", "4-Remote-Exchange");
4280 case LOCATION_PRIVATE_REMOTE:
4281 add_trace("cause", "location", "5-Remote-PBX");
4283 case LOCATION_INTERNATIONAL:
4284 add_trace("cause", "location", "7-International-Exchange");
4286 case LOCATION_BEYOND:
4287 add_trace("cause", "location", "10-Beyond-Interworking");
4290 add_trace("cause", "location", "%d", param->progressinfo.location);
4295 case MESSAGE_INFORMATION:
4296 trace_header("INFORMATION", 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);
4301 if (param->information.id[0])
4302 add_trace("dialing", NULL, "%s", param->information.id);
4303 if (param->information.display[0])
4304 add_trace("display", NULL, "%s", param->information.display);
4305 if (param->information.sending_complete)
4306 add_trace("complete", NULL, "true", param->information.sending_complete);
4310 case MESSAGE_FACILITY:
4311 trace_header("FACILITY", dir);
4312 if (dir == DIRECTION_OUT)
4313 add_trace("to", NULL, "CH(%lu)", port_id);
4314 if (dir == DIRECTION_IN)
4315 add_trace("from", NULL, "CH(%lu)", port_id);
4320 trace_header("TONE", dir);
4321 if (dir == DIRECTION_OUT)
4322 add_trace("to", NULL, "CH(%lu)", port_id);
4323 if (dir == DIRECTION_IN)
4324 add_trace("from", NULL, "CH(%lu)", port_id);
4325 if (param->tone.name[0]) {
4326 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4327 add_trace("name", NULL, "%s", param->tone.name);
4329 add_trace("off", NULL, NULL);
4333 case MESSAGE_SUSPEND:
4334 case MESSAGE_RESUME:
4335 if (message_type == MESSAGE_SUSPEND)
4336 trace_header("SUSPEND", dir);
4338 trace_header("RESUME", dir);
4339 if (dir == DIRECTION_OUT)
4340 add_trace("to", NULL, "CH(%lu)", port_id);
4341 if (dir == DIRECTION_IN)
4342 add_trace("from", NULL, "CH(%lu)", port_id);
4343 if (param->parkinfo.len)
4344 add_trace("length", NULL, "%d", param->parkinfo.len);
4349 case MESSAGE_BCHANNEL:
4350 trace_header("BCHANNEL", dir);
4351 switch(param->bchannel.type) {
4352 case BCHANNEL_REQUEST:
4353 add_trace("type", NULL, "request");
4355 case BCHANNEL_ASSIGN:
4356 add_trace("type", NULL, "assign");
4358 case BCHANNEL_ASSIGN_ACK:
4359 add_trace("type", NULL, "assign_ack");
4361 case BCHANNEL_REMOVE:
4362 add_trace("type", NULL, "remove");
4364 case BCHANNEL_REMOVE_ACK:
4365 add_trace("type", NULL, "remove_ack");
4368 if (param->bchannel.addr)
4369 add_trace("address", NULL, "%x", param->bchannel.addr);
4375 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4379 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4381 struct lcr_msg *message;
4385 if (!portlist->port_id)
4388 if (!e_connectedmode) {
4389 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4390 message->param.disconnectinfo.cause = cause;
4391 message->param.disconnectinfo.location = location;
4393 SCPY(message->param.disconnectinfo.display, display);
4395 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4397 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4399 SCPY(message->param.notifyinfo.display, display);
4401 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4403 message_put(message);
4404 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);