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);
993 if (mISDNport->ifport->remote) {
996 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1001 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1002 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1006 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1008 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);
1010 FATAL("Failed to create Port instance\n");
1011 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
1012 memset(&dialinginfo, 0, sizeof(dialinginfo));
1013 SCPY(dialinginfo.id, e_dialinginfo.id);
1014 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1015 dialinginfo.ntype = e_dialinginfo.ntype;
1016 /* create port_list relation */
1017 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1019 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1021 goto check_anycall_intern;
1023 /* directory.list */
1024 if (e_callerinfo.id[0] && e_ext.display_name) {
1025 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1027 SCPY(e_callerinfo.name, dirname);
1029 // dss1 = (class Pdss1 *)port;
1031 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1032 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1033 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1034 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1035 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1036 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1037 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1038 //terminal if (e_dialinginfo.id)
1039 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1040 /* handle restricted caller ids */
1041 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);
1042 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);
1043 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);
1044 /* display callerid if desired for extension */
1045 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));
1046 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1047 /* use cnip, if enabld */
1048 // if (!e_ext.centrex)
1049 // message->param.setup.callerinfo.name[0] = '\0';
1050 /* screen clip if prefix is required */
1051 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1052 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1053 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1054 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1056 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1057 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1058 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1059 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1061 /* use internal caller id */
1062 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1063 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1064 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1065 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1067 message_put(message);
1068 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1072 /* string from parallel call forward (cfp) */
1075 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1076 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1077 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1081 vbox_only: /* entry point for answering machine only */
1082 cfu_only: /* entry point for cfu */
1083 cfb_only: /* entry point for cfb */
1084 cfnr_only: /* entry point for cfnr */
1085 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1089 /* only if vbox should be dialed, and terminal is given */
1090 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1091 /* go to the end of p */
1094 /* answering vbox call */
1095 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1097 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1098 FATAL("No memory for VBOX Port instance\n");
1099 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1100 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1103 while(*p!=',' && *p!='\0')
1108 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1109 /* hunt for mISDNport and create Port */
1110 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1112 /* creating EXTERNAL port*/
1113 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1116 port = ss5_hunt_line(mISDNport);
1119 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);
1121 FATAL("No memory for Port instance\n");
1122 earlyb = mISDNport->earlyb;
1125 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1126 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1131 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1132 goto check_anycall_intern;
1134 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1135 memset(&dialinginfo, 0, sizeof(dialinginfo));
1136 SCPY(dialinginfo.id, cfp);
1137 dialinginfo.itype = INFO_ITYPE_ISDN;
1138 dialinginfo.ntype = e_dialinginfo.ntype;
1139 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1141 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1143 goto check_anycall_intern;
1145 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1146 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1147 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1148 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1149 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1150 /* if clip is hidden */
1151 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1152 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1153 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1154 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1155 message->param.setup.callerinfo.present = e_ext.callerid_present;
1156 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1158 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1159 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1160 //terminal if (e_dialinginfo.id)
1161 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1162 /* handle restricted caller ids */
1163 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);
1164 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);
1165 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);
1166 /* display callerid if desired for extension */
1167 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));
1168 message_put(message);
1169 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1173 check_anycall_intern:
1174 /* now we have all ports created */
1176 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1178 if (!ea_endpoint->ep_join_id)
1180 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1181 return; /* must exit here */
1185 /* *********************** external call */
1187 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1188 /* call to extenal interfaces */
1189 if (e_dialinginfo.keypad[0])
1190 p = e_dialinginfo.keypad;
1192 p = e_dialinginfo.id;
1195 while(*p!=',' && *p!='\0')
1196 SCCAT(number, *p++);
1200 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");
1201 /* hunt for mISDNport and create Port */
1202 /* hunt for mISDNport and create Port */
1203 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1205 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1206 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1208 goto check_anycall_extern;
1210 /* creating EXTERNAL port*/
1211 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1214 port = ss5_hunt_line(mISDNport);
1218 if (mISDNport->gsm_bs)
1219 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1223 if (mISDNport->gsm_ms)
1224 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1227 if (mISDNport->ifport->remote) {
1228 admin = admin_first;
1230 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1232 admin = admin->next;
1235 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1236 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1240 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1242 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);
1244 FATAL("No memory for Port instance\n");
1245 earlyb = mISDNport->earlyb;
1246 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1247 memset(&dialinginfo, 0, sizeof(dialinginfo));
1248 if (e_dialinginfo.keypad[0])
1249 SCPY(dialinginfo.keypad, number);
1251 SCPY(dialinginfo.id, number);
1252 dialinginfo.itype = INFO_ITYPE_ISDN;
1253 dialinginfo.ntype = e_dialinginfo.ntype;
1254 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1255 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1257 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1259 goto check_anycall_extern;
1261 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1262 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1263 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1264 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1265 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1266 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1267 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1268 //terminal if (e_dialinginfo.id)
1269 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1270 /* handle restricted caller ids */
1271 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);
1272 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);
1273 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);
1274 /* display callerid if desired for extension */
1275 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));
1276 message_put(message);
1277 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1281 check_anycall_extern:
1282 /* now we have all ports created */
1284 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1286 if (!ea_endpoint->ep_join_id)
1288 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1289 return; /* must exit here */
1296 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1298 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1300 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1303 unsched_timer(&ea->e_redial_timeout);
1304 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1305 ea->e_multipoint_cause = 0;
1306 ea->e_multipoint_location = 0;
1307 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1308 ea->e_join_pattern = 0;
1309 ea->process_dialing(1);
1310 /* we must exit, because our endpoint might be gone */
1315 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1317 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1319 if (!ea->e_action) {
1320 unsched_timer(&ea->e_redial_timeout);
1321 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1322 ea->process_dialing(0);
1323 /* we must exit, because our endpoint might be gone */
1329 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1331 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1333 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1335 ea->new_state(EPOINT_STATE_OUT_SETUP);
1336 /* call special setup routine */
1342 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1344 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1346 /* leave power dialing on */
1347 ea->e_powerdial_on = 1;
1348 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1351 ea->e_ruleset = ruleset_main;
1353 ea->e_rule = ea->e_ruleset->rule_first;
1354 ea->e_action = NULL;
1355 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1356 ea->process_dialing(0);
1361 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1363 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1364 struct port_list *portlist;
1365 struct lcr_msg *message;
1367 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1369 /* release all ports */
1370 while((portlist = ea->ea_endpoint->ep_portlist)) {
1371 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1372 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1373 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1374 message_put(message);
1375 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1376 ea->ea_endpoint->free_portlist(portlist);
1379 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1380 message->param.audiopath = 0;
1381 message_put(message);
1382 /* indicate no patterns */
1383 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1384 message_put(message);
1385 /* set setup state, since we have no response from the new join */
1386 ea->new_state(EPOINT_STATE_OUT_SETUP);
1391 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1393 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1395 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);
1401 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1403 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1405 if (ea->e_state == EPOINT_STATE_IDLE) {
1406 /* epoint is idle, check callback */
1407 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1408 ea->new_state(EPOINT_STATE_OUT_SETUP);
1415 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1417 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1419 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1420 struct port_list *portlist;
1422 ea->e_ruleset = ruleset_main;
1424 ea->e_rule = ea->e_ruleset->rule_first;
1425 ea->e_action = NULL;
1426 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1427 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1429 ea->e_connectedmode = 0;
1431 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1432 portlist = ea->ea_endpoint->ep_portlist;
1434 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1435 ea->set_tone(portlist, "cause_10");
1442 /* doing a hookflash */
1443 void EndpointAppPBX::hookflash(void)
1448 /* be sure that we are active */
1450 e_tx_state = NOTIFY_STATE_ACTIVE;
1452 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1454 if (ea_endpoint->ep_use > 1) {
1455 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1458 /* dialtone after pressing the hash key */
1459 process_hangup(e_join_cause, e_join_location);
1460 e_multipoint_cause = 0;
1461 e_multipoint_location = 0;
1462 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1464 port->set_echotest(0);
1466 if (ea_endpoint->ep_join_id) {
1467 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1469 e_ruleset = ruleset_main;
1471 e_rule = e_ruleset->rule_first;
1473 new_state(EPOINT_STATE_IN_OVERLAP);
1474 e_connectedmode = 1;
1475 SCPY(e_dialinginfo.id, e_ext.prefix);
1476 e_extdialing = e_dialinginfo.id;
1478 if (e_dialinginfo.id[0]) {
1479 set_tone(ea_endpoint->ep_portlist, "dialing");
1482 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1490 /* messages from port
1492 /* port MESSAGE_SETUP */
1493 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1495 struct lcr_msg *message;
1497 int writeext; /* flags need to write extension after modification */
1499 struct interface *interface;
1501 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1503 portlist->port_type = param->setup.port_type;
1504 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1505 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1506 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1507 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1509 /* convert (inter-)national number type */
1510 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1511 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1513 // e_dtmf = param->setup.dtmf;
1514 /* screen incoming caller id */
1515 interface = interface_first;
1517 if (!strcmp(e_callerinfo.interface, interface->name)) {
1520 interface = interface->next;
1523 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1524 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1527 /* process extension */
1528 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1529 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1530 /* port makes call from extension */
1531 SCPY(e_callerinfo.extension, e_callerinfo.id);
1532 SCPY(e_ext.number, e_callerinfo.extension);
1533 SCPY(e_extension_interface, e_callerinfo.interface);
1535 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1538 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1539 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1541 /* get extension's info about caller */
1542 if (!read_extension(&e_ext, e_ext.number)) {
1543 /* extension doesn't exist */
1544 trace_header("EXTENSION (not created)", DIRECTION_IN);
1545 add_trace("extension", NULL, "%s", e_ext.number);
1547 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1548 new_state(EPOINT_STATE_OUT_DISCONNECT);
1549 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1550 e_ext.number[0] = '\0'; /* no terminal */
1555 /* put prefix (next) in front of e_dialinginfo.id */
1556 if (e_ext.next[0]) {
1557 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1558 SCPY(e_dialinginfo.id, buffer);
1559 e_ext.next[0] = '\0';
1561 } else if (e_ext.prefix[0]) {
1562 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1563 SCPY(e_dialinginfo.id, buffer);
1566 /* screen caller id by extension's config */
1567 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1569 SCPY(e_callerinfo.name, e_ext.name);
1570 /* use caller id (or if exist: id_next_call) for this call */
1571 if (e_ext.id_next_call_present >= 0) {
1572 SCPY(e_callerinfo.id, e_ext.id_next_call);
1573 /* if we restrict the pesentation */
1574 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1575 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1576 else e_callerinfo.present = e_ext.id_next_call_present;
1577 e_callerinfo.ntype = e_ext.id_next_call_type;
1578 e_ext.id_next_call_present = -1;
1581 SCPY(e_callerinfo.id, e_ext.callerid);
1582 /* if we restrict the pesentation */
1583 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1584 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1585 else e_callerinfo.present = e_ext.callerid_present;
1586 e_callerinfo.ntype = e_ext.callerid_type;
1588 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1590 /* extension is written */
1592 write_extension(&e_ext, e_ext.number);
1594 /* set volume of rx and tx */
1595 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1596 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1597 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1598 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1599 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1600 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1601 message_put(message);
1604 /* start recording if enabled */
1605 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1606 /* check if we are a terminal */
1607 if (e_ext.number[0] == '\0')
1608 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1610 port = find_port_id(portlist->port_id);
1612 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1616 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1617 /* no terminal identification */
1618 e_ext.number[0] = '\0';
1619 e_extension_interface[0] = '\0';
1620 memset(&e_ext, 0, sizeof(e_ext));
1621 e_ext.rights = 4; /* right to dial internat */
1625 e_ruleset = ruleset_main;
1627 e_rule = e_ruleset->rule_first;
1629 e_extdialing = e_dialinginfo.id;
1630 new_state(EPOINT_STATE_IN_SETUP);
1631 if (e_dialinginfo.id[0]) {
1632 set_tone(portlist, "dialing");
1634 if (e_ext.number[0])
1635 set_tone(portlist, "dialpbx");
1637 set_tone(portlist, "dialtone");
1640 if (e_state == EPOINT_STATE_IN_SETUP) {
1641 /* request MORE info, if not already at higher state */
1642 new_state(EPOINT_STATE_IN_OVERLAP);
1643 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1644 message_put(message);
1645 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1649 /* port MESSAGE_INFORMATION */
1650 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1652 struct lcr_msg *message;
1654 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1656 /* ignore information message without digit information */
1657 if (!param->information.id[0])
1662 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1664 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1669 /* if vbox_play is done, the information are just used as they come */
1671 if (e_action->index == ACTION_VBOX_PLAY) {
1672 /* concat dialing string */
1673 SCAT(e_dialinginfo.id, param->information.id);
1678 /* keypad when disconnect but in connected mode */
1679 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1680 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1681 /* processing keypad function */
1682 if (param->information.id[0] == '0') {
1688 /* keypad when connected */
1689 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1690 if (e_enablekeypad) {
1691 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1692 memcpy(&message->param, param, sizeof(union parameter));
1693 message_put(message);
1697 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1698 /* processing keypad function */
1699 if (param->information.id[0] == '0') {
1702 if (param->information.id[0])
1703 keypad_function(param->information.id[0]);
1705 if (e_ext.number[0])
1706 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1708 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1713 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1714 if (e_ext.number[0])
1715 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1717 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1721 if (!param->information.id[0])
1723 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1724 set_tone(portlist, "dialing");
1727 if (e_action->index==ACTION_OUTDIAL
1728 || e_action->index==ACTION_EXTERNAL
1729 || e_action->index==ACTION_REMOTE) {
1731 set_tone(portlist, "dialing");
1732 else if (!e_extdialing[0])
1733 set_tone(portlist, "dialing");
1735 /* concat dialing string */
1736 SCAT(e_dialinginfo.id, param->information.id);
1740 /* port MESSAGE_DTMF */
1741 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1744 struct lcr_msg *message;
1748 /* only if dtmf detection is enabled */
1750 trace_header("DTMF (disabled)", DIRECTION_IN);
1754 trace_header("DTMF", DIRECTION_IN);
1755 add_trace("digit", NULL, "%c", param->dtmf);
1759 NOTE: vbox is now handled due to overlap state
1760 /* if vbox_play is done, the dtmf digits are just used as they come */
1762 if (e_action->index == ACTION_VBOX_PLAY) {
1763 /* concat dialing string */
1764 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1765 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1766 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1769 /* continue to process *X# sequences */
1773 /* check for *X# sequence */
1774 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1775 if (e_enablekeypad) {
1776 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1777 memcpy(&message->param, param, sizeof(union parameter));
1778 message_put(message);
1781 if (e_dtmf_time+3 < now) {
1782 /* the last digit was too far in the past to be a sequence */
1783 if (param->dtmf == '*')
1784 /* only start is allowed in the sequence */
1789 /* we have a sequence of digits, see what we got */
1790 if (param->dtmf == '*')
1792 else if (param->dtmf>='0' && param->dtmf<='9') {
1793 /* we need to have a star before we receive the digit of the sequence */
1794 if (e_dtmf_last == '*')
1795 e_dtmf_last = param->dtmf;
1796 } else if (param->dtmf == '#') {
1798 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1799 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1800 if (e_dtmf_last == '0') {
1804 /* processing keypad function */
1806 keypad_function(e_dtmf_last);
1812 /* set last time of dtmf */
1817 /* check for ## hookflash during dialing */
1819 if (e_action->index==ACTION_PASSWORD
1820 || e_action->index==ACTION_PASSWORD_WRITE)
1822 if (param->dtmf=='#') { /* current digit is '#' */
1823 if (e_state==EPOINT_STATE_IN_DISCONNECT
1824 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1838 /* dialing using dtmf digit */
1839 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1840 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1841 set_tone(portlist, "dialing");
1843 /* concat dialing string */
1844 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1845 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1846 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1852 /* port MESSAGE_CRYPT */
1853 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1855 /* send crypt response to cryptman */
1856 if (param->crypt.type == CR_MESSAGE_IND)
1857 cryptman_msg2man(param->crypt.data, param->crypt.len);
1859 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1862 /* port MESSAGE_OVERLAP */
1863 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1865 struct lcr_msg *message;
1867 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1869 /* signal to call tool */
1870 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1872 if (e_dialing_queue[0] && portlist) {
1873 /* send what we have not dialed yet, because we had no setup complete */
1874 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1875 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1876 SCPY(message->param.information.id, e_dialing_queue);
1877 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1878 message_put(message);
1879 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1880 e_dialing_queue[0] = '\0';
1882 /* check if pattern is available */
1883 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1884 /* indicate patterns */
1885 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1886 message_put(message);
1888 /* connect audio, if not already */
1889 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1890 message->param.audiopath = 1;
1891 message_put(message);
1893 /* indicate no patterns */
1894 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1895 message_put(message);
1897 /* disconnect audio, if not already */
1898 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1899 message->param.audiopath = 0;
1900 message_put(message);
1902 new_state(EPOINT_STATE_OUT_OVERLAP);
1903 /* if we are in a join */
1904 if (ea_endpoint->ep_join_id) {
1905 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1906 memcpy(&message->param, param, sizeof(union parameter));
1907 message_put(message);
1911 /* port MESSAGE_PROCEEDING */
1912 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1914 struct lcr_msg *message;
1916 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1918 /* signal to call tool */
1919 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1921 e_state = EPOINT_STATE_OUT_PROCEEDING;
1922 /* check if pattern is availatle */
1923 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1924 /* indicate patterns */
1925 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1926 message_put(message);
1928 /* connect audio, if not already */
1929 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1930 message->param.audiopath = 1;
1931 message_put(message);
1933 /* indicate no patterns */
1934 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1935 message_put(message);
1937 /* disconnect audio, if not already */
1938 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1939 message->param.audiopath = 0;
1940 message_put(message);
1942 /* if we are in a call */
1943 if (ea_endpoint->ep_join_id) {
1944 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1945 memcpy(&message->param, param, sizeof(union parameter));
1946 message_put(message);
1950 /* port MESSAGE_ALERTING */
1951 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1953 struct lcr_msg *message;
1955 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1957 /* signal to call tool */
1958 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1961 // set_tone(portlist, "hold");
1963 new_state(EPOINT_STATE_OUT_ALERTING);
1964 /* check if pattern is available */
1965 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1966 /* indicate patterns */
1967 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1968 message_put(message);
1970 /* connect audio, if not already */
1971 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1972 message->param.audiopath = 1;
1973 message_put(message);
1975 /* indicate no patterns */
1976 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1977 message_put(message);
1979 /* disconnect audio, if not already */
1980 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1981 message->param.audiopath = 0;
1982 message_put(message);
1984 /* if we are in a call */
1985 if (ea_endpoint->ep_join_id) {
1986 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1987 memcpy(&message->param, param, sizeof(union parameter));
1988 message_put(message);
1992 /* port MESSAGE_CONNECT */
1993 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1995 struct lcr_msg *message;
1997 unsigned int port_id = portlist->port_id;
1998 struct port_list *tportlist;
2000 struct interface *interface;
2003 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2005 /* signal to call tool */
2006 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
2008 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
2009 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2010 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
2011 tportlist = ea_endpoint->ep_portlist;
2012 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2013 tportlist = tportlist->next;
2014 if (tportlist->port_id == port_id)
2015 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2016 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2017 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
2018 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2019 message_put(message);
2020 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
2021 ea_endpoint->free_portlist(tportlist);
2023 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2028 /* screen incoming connected id */
2029 interface = interface_first;
2031 if (!strcmp(e_connectinfo.interface, interface->name)) {
2034 interface = interface->next;
2037 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
2039 /* screen connected name */
2041 SCPY(e_connectinfo.name, e_ext.name);
2043 /* add internal id to colp */
2044 SCPY(e_connectinfo.extension, e_ext.number);
2046 /* we store the connected port number */
2047 SCPY(e_extension_interface, e_connectinfo.interface);
2049 /* for internal and am calls, we get the extension's id */
2050 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
2051 SCPY(e_connectinfo.id, e_ext.callerid);
2052 SCPY(e_connectinfo.extension, e_ext.number);
2053 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2054 e_connectinfo.ntype = e_ext.callerid_type;
2055 e_connectinfo.present = e_ext.callerid_present;
2057 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2058 e_connectinfo.itype = INFO_ITYPE_VBOX;
2059 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2062 new_state(EPOINT_STATE_CONNECT);
2064 /* set volume of rx and tx */
2065 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2066 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2067 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2068 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2069 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2070 message_put(message);
2073 unsched_timer(&e_cfnr_timeout);
2074 unsched_timer(&e_cfnr_call_timeout);
2075 if (e_ext.number[0])
2076 e_dtmf = 1; /* allow dtmf */
2079 /* other calls with no caller id (or not available for the extension) and force colp */
2080 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2081 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2082 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
2083 /* external extension answered */
2084 port = find_port_id(portlist->port_id);
2086 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2087 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2092 /* send connect to join */
2093 if (ea_endpoint->ep_join_id) {
2094 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2095 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2096 message_put(message);
2098 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2099 message->param.audiopath = 1;
2100 message_put(message);
2101 } else if (!e_adminid) {
2103 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2104 SCPY(e_ext.number, e_cbcaller);
2105 new_state(EPOINT_STATE_IN_OVERLAP);
2106 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2108 /* get extension's info about terminal */
2109 if (!read_extension(&e_ext, e_ext.number)) {
2110 /* extension doesn't exist */
2111 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2112 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2113 new_state(EPOINT_STATE_OUT_DISCONNECT);
2114 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2118 /* put prefix in front of e_cbdialing */
2119 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2120 SCPY(e_dialinginfo.id, buffer);
2121 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2122 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2124 /* use caller id (or if exist: id_next_call) for this call */
2125 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2126 SCPY(e_callerinfo.extension, e_ext.number);
2127 if (e_ext.id_next_call_present >= 0) {
2128 SCPY(e_callerinfo.id, e_ext.id_next_call);
2129 e_callerinfo.present = e_ext.id_next_call_present;
2130 e_callerinfo.ntype = e_ext.id_next_call_type;
2131 e_ext.id_next_call_present = -1;
2132 /* extension is written */
2133 write_extension(&e_ext, e_ext.number);
2135 SCPY(e_callerinfo.id, e_ext.callerid);
2136 e_callerinfo.present = e_ext.callerid_present;
2137 e_callerinfo.ntype = e_ext.callerid_type;
2139 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2141 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2144 /* check if caller id is NOT authenticated */
2145 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2146 /* make call state to enter password */
2147 new_state(EPOINT_STATE_IN_OVERLAP);
2148 e_action = &action_password_write;
2149 unsched_timer(&e_match_timeout);
2150 e_match_to_action = NULL;
2151 e_dialinginfo.id[0] = '\0';
2152 e_extdialing = strchr(e_dialinginfo.id, '\0');
2153 schedule_timer(&e_password_timeout, 20, 0);
2156 /* incoming call (callback) */
2157 e_ruleset = ruleset_main;
2159 e_rule = e_ruleset->rule_first;
2161 e_extdialing = e_dialinginfo.id;
2162 if (e_dialinginfo.id[0]) {
2163 set_tone(portlist, "dialing");
2166 set_tone(portlist, "dialpbx");
2169 } else { /* testcall */
2170 set_tone(portlist, "hold");
2173 /* start recording if enabled, not when answering machine answers */
2174 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)) {
2175 /* check if we are a terminal */
2176 if (e_ext.number[0] == '\0')
2177 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2179 port = find_port_id(portlist->port_id);
2181 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2186 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2187 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2189 struct lcr_msg *message;
2191 unsigned int port_id = portlist->port_id;
2195 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2197 /* signal to call tool */
2198 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2200 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2201 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2202 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2207 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);
2208 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2209 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2211 /* check if we have more than one portlist relation and we just ignore the disconnect */
2212 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2213 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2214 portlist = ea_endpoint->ep_portlist;
2216 if (portlist->port_id == port_id)
2218 portlist = portlist->next;
2221 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2222 if (message_type != MESSAGE_RELEASE) {
2223 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2224 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2225 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2226 message_put(message);
2227 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2229 ea_endpoint->free_portlist(portlist);
2230 return; /* one relation removed */
2232 if (e_state == EPOINT_STATE_CONNECT) {
2233 /* use cause from port after connect */
2234 cause = param->disconnectinfo.cause;
2235 location = param->disconnectinfo.location;
2237 /* use multipoint cause if no connect yet */
2238 if (e_multipoint_cause) {
2239 cause = e_multipoint_cause;
2240 location = e_multipoint_location;
2242 cause = CAUSE_NOUSER;
2243 location = LOCATION_PRIVATE_LOCAL;
2247 unsched_timer(&e_cfnr_timeout);
2248 unsched_timer(&e_cfnr_call_timeout);
2250 /* process hangup */
2251 process_hangup(e_join_cause, e_join_location);
2252 e_multipoint_cause = 0;
2253 e_multipoint_location = 0;
2255 if (message_type == MESSAGE_DISCONNECT) {
2256 /* tone to disconnected end */
2257 SPRINT(buffer, "cause_%02x", cause);
2258 if (ea_endpoint->ep_portlist)
2259 set_tone(ea_endpoint->ep_portlist, buffer);
2261 new_state(EPOINT_STATE_IN_DISCONNECT);
2264 if (ea_endpoint->ep_join_id) {
2265 int haspatterns = 0;
2266 /* check if pattern is available */
2267 if (ea_endpoint->ep_portlist)
2268 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2269 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
2270 && message_type != MESSAGE_RELEASE) // if we release, we are done
2273 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2274 /* indicate patterns */
2275 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2276 message_put(message);
2277 /* connect audio, if not already */
2278 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2279 message->param.audiopath = 1;
2280 message_put(message);
2281 /* send disconnect */
2282 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2283 memcpy(&message->param, param, sizeof(union parameter));
2284 message_put(message);
2285 /* disable encryption if disconnected */
2286 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2288 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2291 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2294 if (message_type == MESSAGE_RELEASE)
2295 ea_endpoint->free_portlist(portlist);
2296 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2297 return; /* must exit here */
2300 /* port MESSAGE_TIMEOUT */
2301 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2305 trace_header("TIMEOUT", DIRECTION_IN);
2306 message_type = MESSAGE_DISCONNECT;
2307 switch (param->state) {
2308 case PORT_STATE_OUT_SETUP:
2309 case PORT_STATE_OUT_OVERLAP:
2310 add_trace("state", NULL, "outgoing setup/dialing");
2312 /* no user responding */
2313 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2314 return; /* must exit here */
2316 case PORT_STATE_IN_SETUP:
2317 case PORT_STATE_IN_OVERLAP:
2318 add_trace("state", NULL, "incoming setup/dialing");
2319 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2320 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2323 case PORT_STATE_OUT_PROCEEDING:
2324 add_trace("state", NULL, "outgoing proceeding");
2326 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2327 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2328 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2329 return; /* must exit here */
2331 case PORT_STATE_IN_PROCEEDING:
2332 add_trace("state", NULL, "incoming proceeding");
2333 param->disconnectinfo.cause = CAUSE_NOUSER;
2334 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2337 case PORT_STATE_OUT_ALERTING:
2338 add_trace("state", NULL, "outgoing alerting");
2340 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2341 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2342 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2343 return; /* must exit here */
2345 case PORT_STATE_CONNECT:
2346 add_trace("state", NULL, "connect");
2348 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2349 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2350 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2351 return; /* must exit here */
2353 case PORT_STATE_IN_ALERTING:
2354 add_trace("state", NULL, "incoming alerting");
2355 param->disconnectinfo.cause = CAUSE_NOANSWER;
2356 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2359 case PORT_STATE_IN_DISCONNECT:
2360 case PORT_STATE_OUT_DISCONNECT:
2361 add_trace("state", NULL, "disconnect");
2363 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2364 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2365 return; /* must exit here */
2368 param->disconnectinfo.cause = 31; /* normal unspecified */
2369 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2372 /* release call, disconnect isdn */
2374 new_state(EPOINT_STATE_OUT_DISCONNECT);
2375 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2376 SCPY(e_tone, cause);
2378 set_tone(portlist, cause);
2379 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2380 portlist = portlist->next;
2382 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2385 /* port MESSAGE_NOTIFY */
2386 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2388 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2390 struct lcr_msg *message;
2391 const char *logtext = "";
2394 /* signal to call tool */
2395 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);
2396 if (param->notifyinfo.notify) {
2397 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2400 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2401 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2402 case INFO_NOTIFY_REMOTE_HOLD:
2403 case INFO_NOTIFY_USER_SUSPENDED:
2404 /* tell call about it */
2405 if (ea_endpoint->ep_join_id) {
2406 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2407 message->param.audiopath = 0;
2408 message_put(message);
2412 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2413 case INFO_NOTIFY_USER_RESUMED:
2414 /* set volume of rx and tx */
2415 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2416 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2418 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2419 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2420 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2421 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2422 message_put(message);
2424 /* set current tone */
2426 set_tone(portlist, e_tone);
2427 /* tell call about it */
2428 if (ea_endpoint->ep_join_id) {
2429 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2430 message->param.audiopath = 1;
2431 message_put(message);
2436 /* get name of notify */
2437 switch(param->notifyinfo.notify) {
2442 logtext = "USER_SUSPENDED";
2445 logtext = "BEARER_SERVICE_CHANGED";
2448 logtext = "USER_RESUMED";
2451 logtext = "CONFERENCE_ESTABLISHED";
2454 logtext = "CONFERENCE_DISCONNECTED";
2457 logtext = "OTHER_PARTY_ADDED";
2460 logtext = "ISOLATED";
2463 logtext = "REATTACHED";
2466 logtext = "OTHER_PARTY_ISOLATED";
2469 logtext = "OTHER_PARTY_REATTACHED";
2472 logtext = "OTHER_PARTY_SPLIT";
2475 logtext = "OTHER_PARTY_DISCONNECTED";
2478 logtext = "CONFERENCE_FLOATING";
2481 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2484 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2487 logtext = "CALL_IS_A_WAITING_CALL";
2490 logtext = "DIVERSION_ACTIVATED";
2493 logtext = "RESERVED_CT_1";
2496 logtext = "RESERVED_CT_2";
2499 logtext = "REVERSE_CHARGING";
2502 logtext = "REMOTE_HOLD";
2505 logtext = "REMOTE_RETRIEVAL";
2508 logtext = "CALL_IS_DIVERTING";
2511 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2516 /* notify call if available */
2517 if (ea_endpoint->ep_join_id) {
2518 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2519 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2520 message_put(message);
2525 /* port MESSAGE_PROGRESS */
2526 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2528 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2530 struct lcr_msg *message;
2532 /* signal to call tool */
2533 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2535 /* send progress to call if available */
2536 if (ea_endpoint->ep_join_id) {
2537 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2538 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2539 message_put(message);
2544 /* port MESSAGE_FACILITY */
2545 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2547 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2549 struct lcr_msg *message;
2551 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2552 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2553 message_put(message);
2556 /* port MESSAGE_SUSPEND */
2557 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2558 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2560 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2562 /* epoint is now parked */
2563 ea_endpoint->ep_park = 1;
2564 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2565 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2567 /* remove port relation */
2568 ea_endpoint->free_portlist(portlist);
2571 /* port MESSAGE_RESUME */
2572 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2573 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2575 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2577 /* epoint is now resumed */
2578 ea_endpoint->ep_park = 0;
2582 /* port MESSAGE_ENABLEKEYPAD */
2583 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2585 struct lcr_msg *message;
2587 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2589 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2590 memcpy(&message->param, param, sizeof(union parameter));
2591 message_put(message);
2595 /* port sends message to the endpoint
2597 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2599 struct port_list *portlist;
2601 portlist = ea_endpoint->ep_portlist;
2603 if (port_id == portlist->port_id)
2605 portlist = portlist->next;
2608 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);
2612 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2613 switch(message_type) {
2614 case MESSAGE_DATA: /* data from port */
2615 /* check if there is a call */
2616 if (!ea_endpoint->ep_join_id)
2618 /* continue if only one portlist */
2619 if (ea_endpoint->ep_portlist->next != NULL)
2621 /* forward message */
2622 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2625 case MESSAGE_TONE_EOF: /* tone is end of file */
2626 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2628 if (e_action->index == ACTION_VBOX_PLAY) {
2631 if (e_action->index == ACTION_EFI) {
2637 case MESSAGE_TONE_COUNTER: /* counter info received */
2638 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);
2640 if (e_action->index == ACTION_VBOX_PLAY) {
2641 e_vbox_counter = param->counter.current;
2642 if (param->counter.max >= 0)
2643 e_vbox_counter_max = param->counter.max;
2647 /* PORT sends SETUP message */
2649 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);
2650 if (e_state!=EPOINT_STATE_IDLE) {
2651 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2654 port_setup(portlist, message_type, param);
2657 /* PORT sends INFORMATION message */
2658 case MESSAGE_INFORMATION: /* additional digits received */
2659 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);
2660 port_information(portlist, message_type, param);
2663 /* PORT sends FACILITY message */
2664 case MESSAGE_FACILITY:
2665 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2666 port_facility(portlist, message_type, param);
2669 /* PORT sends DTMF message */
2670 case MESSAGE_DTMF: /* dtmf digits received */
2671 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);
2672 port_dtmf(portlist, message_type, param);
2675 /* PORT sends CRYPT message */
2676 case MESSAGE_CRYPT: /* crypt response received */
2677 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2678 port_crypt(portlist, message_type, param);
2681 /* PORT sends MORE message */
2682 case MESSAGE_OVERLAP:
2683 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);
2684 if (e_state != EPOINT_STATE_OUT_SETUP) {
2685 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);
2688 port_overlap(portlist, message_type, param);
2691 /* PORT sends PROCEEDING message */
2692 case MESSAGE_PROCEEDING: /* port is proceeding */
2693 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);
2694 if (e_state!=EPOINT_STATE_OUT_SETUP
2695 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2696 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);
2699 port_proceeding(portlist, message_type, param);
2702 /* PORT sends ALERTING message */
2703 case MESSAGE_ALERTING:
2704 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);
2705 if (e_state!=EPOINT_STATE_OUT_SETUP
2706 && e_state!=EPOINT_STATE_OUT_OVERLAP
2707 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2708 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);
2711 port_alerting(portlist, message_type, param);
2714 /* PORT sends CONNECT message */
2715 case MESSAGE_CONNECT:
2716 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);
2717 if (e_state!=EPOINT_STATE_OUT_SETUP
2718 && e_state!=EPOINT_STATE_OUT_OVERLAP
2719 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2720 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2721 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2724 port_connect(portlist, message_type, param);
2727 /* PORT sends DISCONNECT message */
2728 case MESSAGE_DISCONNECT: /* port is disconnected */
2729 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);
2730 port_disconnect_release(portlist, message_type, param);
2733 /* PORT sends a RELEASE message */
2734 case MESSAGE_RELEASE: /* port releases */
2735 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);
2736 /* portlist is release at port_disconnect_release, thanx Paul */
2737 port_disconnect_release(portlist, message_type, param);
2740 /* PORT sends a TIMEOUT message */
2741 case MESSAGE_TIMEOUT:
2742 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);
2743 port_timeout(portlist, message_type, param);
2744 break; /* release */
2746 /* PORT sends a NOTIFY message */
2747 case MESSAGE_NOTIFY:
2748 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);
2749 port_notify(portlist, message_type, param);
2752 /* PORT sends a PROGRESS message */
2753 case MESSAGE_PROGRESS:
2754 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);
2755 port_progress(portlist, message_type, param);
2758 /* PORT sends a SUSPEND message */
2759 case MESSAGE_SUSPEND:
2760 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);
2761 port_suspend(portlist, message_type, param);
2762 break; /* suspend */
2764 /* PORT sends a RESUME message */
2765 case MESSAGE_RESUME:
2766 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);
2767 port_resume(portlist, message_type, param);
2771 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2772 /* port assigns bchannel */
2773 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2774 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);
2775 /* only one port is expected to be connected to bchannel */
2776 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2777 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2781 /* PORT requests DTMF */
2782 case MESSAGE_ENABLEKEYPAD:
2783 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);
2784 port_enablekeypad(portlist, message_type, param);
2789 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);
2792 /* Note: this endpoint may be destroyed, so we MUST return */
2796 /* messages from join
2798 /* join MESSAGE_CRYPT */
2799 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2801 switch(param->crypt.type) {
2802 /* message from remote port to "crypt manager" */
2803 case CU_ACTK_REQ: /* activate key-exchange */
2804 case CU_ACTS_REQ: /* activate shared key */
2805 case CU_DACT_REQ: /* deactivate */
2806 case CU_INFO_REQ: /* request last info message */
2807 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2810 /* message from "crypt manager" to user */
2811 case CU_ACTK_CONF: /* key-echange done */
2812 case CU_ACTS_CONF: /* shared key done */
2813 case CU_DACT_CONF: /* deactivated */
2814 case CU_DACT_IND: /* deactivated */
2815 case CU_ERROR_IND: /* receive error message */
2816 case CU_INFO_IND: /* receive info message */
2817 case CU_INFO_CONF: /* receive info message */
2818 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2822 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);
2826 /* join MESSAGE_INFORMATION */
2827 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2829 struct lcr_msg *message;
2834 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2835 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2836 message_put(message);
2837 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2838 portlist = portlist->next;
2842 /* join MESSAGE_FACILITY */
2843 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2845 struct lcr_msg *message;
2847 if (!e_ext.facility && e_ext.number[0]) {
2852 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2853 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2854 message_put(message);
2855 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2856 portlist = portlist->next;
2860 /* join MESSAGE_MORE */
2861 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2863 struct lcr_msg *message;
2865 new_state(EPOINT_STATE_IN_OVERLAP);
2868 if (e_join_pattern && e_ext.own_setup) {
2869 /* disconnect audio */
2870 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2871 message->param.audiopath = 0;
2872 message_put(message);
2874 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2875 if (e_dialinginfo.id[0])
2876 set_tone(portlist, "dialing");
2878 set_tone(portlist, "dialtone");
2881 if (e_dialinginfo.id[0]) {
2882 set_tone(portlist, "dialing");
2884 if (e_ext.number[0])
2885 set_tone(portlist, "dialpbx");
2887 set_tone(portlist, "dialtone");
2891 /* join MESSAGE_PROCEEDING */
2892 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2894 struct lcr_msg *message;
2896 new_state(EPOINT_STATE_IN_PROCEEDING);
2898 /* own proceeding tone */
2899 if (e_join_pattern) {
2900 /* connect / disconnect audio */
2901 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2902 if (e_ext.own_proceeding)
2903 message->param.audiopath = 0;
2905 message->param.audiopath = 1;
2906 message_put(message);
2908 // UCPY(e_join_tone, "proceeding");
2910 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2911 message_put(message);
2912 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2914 set_tone(portlist, "proceeding");
2917 /* join MESSAGE_ALERTING */
2918 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2920 struct lcr_msg *message;
2922 new_state(EPOINT_STATE_IN_ALERTING);
2924 /* own alerting tone */
2925 if (e_join_pattern) {
2926 /* connect / disconnect audio */
2927 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2928 if (e_ext.own_alerting)
2929 message->param.audiopath = 0;
2931 message->param.audiopath = 1;
2932 message_put(message);
2935 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2936 message_put(message);
2937 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2939 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2940 set_tone(portlist, "ringing");
2943 if (e_ext.number[0])
2944 set_tone(portlist, "ringpbx");
2946 set_tone(portlist, "ringing");
2948 if (e_ext.number[0])
2949 e_dtmf = 1; /* allow dtmf */
2952 /* join MESSAGE_CONNECT */
2953 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2955 struct lcr_msg *message;
2958 new_state(EPOINT_STATE_CONNECT);
2959 // UCPY(e_join_tone, "");
2961 if (e_ext.number[0])
2962 e_dtmf = 1; /* allow dtmf */
2965 unsched_timer(&e_powerdial_timeout);
2966 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2968 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2969 memcpy(&message->param, param, sizeof(union parameter));
2971 /* screen clip if prefix is required */
2972 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2973 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2974 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2975 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2978 /* use internal caller id */
2979 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2980 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2981 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2984 /* handle restricted caller ids */
2985 apply_callerid_restriction(&e_ext, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
2986 /* display callerid if desired for extension */
2987 SCPY(message->param.connectinfo.display, apply_callerid_display(message->param.connectinfo.id, message->param.connectinfo.itype, message->param.connectinfo.ntype, message->param.connectinfo.present, message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name));
2989 /* use conp, if enabld */
2990 // if (!e_ext.centrex)
2991 // message->param.connectinfo.name[0] = '\0';
2994 message_put(message);
2995 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2997 set_tone(portlist, NULL);
2999 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3000 message->param.audiopath = 1;
3001 message_put(message);
3006 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3007 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3010 struct lcr_msg *message;
3011 struct port_list *portlist = NULL;
3015 /* be sure that we are active */
3017 e_tx_state = NOTIFY_STATE_ACTIVE;
3019 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
3020 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
3021 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
3023 /* set time for power dialing */
3024 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
3027 /* set redial tone */
3028 if (ea_endpoint->ep_portlist) {
3031 set_tone(ea_endpoint->ep_portlist, "redial");
3032 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') redialing in %d seconds\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, (int)e_powerdelay);
3033 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3034 if (e_state==EPOINT_STATE_IN_OVERLAP) {
3035 new_state(EPOINT_STATE_IN_PROCEEDING);
3036 if (ea_endpoint->ep_portlist) {
3037 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3038 message_put(message);
3039 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3041 /* caused the error, that the first knock sound was not there */
3042 /* set_tone(portlist, "proceeding"); */
3044 /* send display of powerdialing */
3045 if (e_ext.display_dialing) {
3046 portlist = ea_endpoint->ep_portlist;
3048 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3050 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3052 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3053 message_put(message);
3054 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3055 portlist = portlist->next;
3065 if ((e_state!=EPOINT_STATE_CONNECT
3066 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3067 && e_state!=EPOINT_STATE_IN_OVERLAP
3068 && e_state!=EPOINT_STATE_IN_PROCEEDING
3069 && e_state!=EPOINT_STATE_IN_ALERTING)
3070 || !ea_endpoint->ep_portlist) { /* or no port */
3071 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3072 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3073 return; /* must exit here */
3076 if (!e_join_cause) {
3077 e_join_cause = param->disconnectinfo.cause;
3078 e_join_location = param->disconnectinfo.location;
3081 /* on release we need the audio again! */
3082 if (message_type == MESSAGE_RELEASE) {
3084 ea_endpoint->ep_join_id = 0;
3086 /* disconnect and select tone */
3087 new_state(EPOINT_STATE_OUT_DISCONNECT);
3088 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3089 /* if own_cause, we must release the join */
3090 if (e_ext.own_cause /* own cause */
3091 || !e_join_pattern) { /* no patterns */
3092 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);
3093 if (message_type != MESSAGE_RELEASE)
3094 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3096 } else { /* else we enable audio */
3097 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3098 message->param.audiopath = 1;
3099 message_put(message);
3101 /* send disconnect message */
3102 SCPY(e_tone, cause);
3103 portlist = ea_endpoint->ep_portlist;
3105 set_tone(portlist, cause);
3106 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3107 portlist = portlist->next;
3111 /* join MESSAGE_SETUP */
3112 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3114 struct lcr_msg *message;
3115 // struct interface *interface;
3117 /* if we already in setup state, we just update the dialing with new digits */
3118 if (e_state == EPOINT_STATE_OUT_SETUP
3119 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3120 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3121 /* if digits changed, what we have already dialed */
3122 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3123 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);
3124 /* release all ports */
3125 while((portlist = ea_endpoint->ep_portlist)) {
3126 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3127 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3128 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3129 message_put(message);
3130 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3131 ea_endpoint->free_portlist(portlist);
3134 /* disconnect audio */
3135 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3136 message->param.audiopath = 0;
3137 message_put(message);
3139 /* get dialing info */
3140 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3141 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3142 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3143 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3144 new_state(EPOINT_STATE_OUT_OVERLAP);
3147 schedule_timer(&e_redial_timeout, 1, 0);
3150 /* if we have a pending redial, so we just adjust the dialing number */
3151 if (e_redial_timeout.active) {
3152 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);
3153 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3156 if (!ea_endpoint->ep_portlist) {
3157 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3159 if (ea_endpoint->ep_portlist->next) {
3160 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3162 if (e_state == EPOINT_STATE_OUT_SETUP) {
3164 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);
3165 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3168 /* get what we have not dialed yet */
3169 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));
3170 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3171 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3172 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3173 message_put(message);
3174 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3176 /* always store what we have dialed or queued */
3177 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3181 if (e_state != EPOINT_STATE_IDLE) {
3182 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3185 /* if an internal extension is dialed, copy that number */
3186 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3187 SCPY(e_ext.number, param->setup.dialinginfo.id);
3188 /* if an internal extension is dialed, get extension's info about caller */
3189 if (e_ext.number[0]) {
3190 if (!read_extension(&e_ext, e_ext.number)) {
3191 e_ext.number[0] = '\0';
3192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3196 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3197 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3198 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3199 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3201 /* process (voice over) data calls */
3202 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3203 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3204 memset(&e_capainfo, 0, sizeof(e_capainfo));
3205 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3206 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3207 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3210 new_state(EPOINT_STATE_OUT_SETUP);
3211 /* call special setup routine */
3215 /* join MESSAGE_mISDNSIGNAL */
3216 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3218 struct lcr_msg *message;
3221 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3222 memcpy(&message->param, param, sizeof(union parameter));
3223 message_put(message);
3224 portlist = portlist->next;
3228 /* join MESSAGE_NOTIFY */
3229 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3231 struct lcr_msg *message;
3234 if (param->notifyinfo.notify) {
3235 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3236 // /* if notification was generated locally, we turn hold music on/off */
3237 // if (param->notifyinfo.local)
3238 // 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)
3242 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3243 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3245 set_tone(portlist, "");
3246 portlist = portlist->next;
3249 portlist = ea_endpoint->ep_portlist;
3254 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3256 set_tone(portlist, "hold");
3257 portlist = portlist->next;
3259 portlist = ea_endpoint->ep_portlist;
3264 /* save new state */
3265 e_tx_state = new_state;
3268 /* notify port(s) about it */
3270 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3271 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3272 /* handle restricted caller ids */
3273 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3274 /* display callerid if desired for extension */
3275 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));
3276 message_put(message);
3277 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3278 portlist = portlist->next;
3282 /* join MESSAGE_DTMF */
3283 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3285 struct lcr_msg *message;
3288 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3289 memcpy(&message->param, param, sizeof(union parameter));
3290 message_put(message);
3291 portlist = portlist->next;
3295 /* JOIN sends messages to the endpoint
3297 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3299 struct port_list *portlist;
3300 struct lcr_msg *message;
3303 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3307 portlist = ea_endpoint->ep_portlist;
3309 /* send MESSAGE_DATA to port */
3310 if (message_type == MESSAGE_DATA) {
3311 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3312 /* skip if no port relation */
3315 /* skip if more than one port relation */
3318 /* forward audio data to port */
3319 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3324 // 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);
3325 switch(message_type) {
3326 /* JOIN SENDS TONE message */
3328 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);
3329 set_tone(portlist, param->tone.name);
3332 /* JOIN SENDS CRYPT message */
3334 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);
3335 join_crypt(portlist, message_type, param);
3338 /* JOIN sends INFORMATION message */
3339 case MESSAGE_INFORMATION:
3340 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);
3341 join_information(portlist, message_type, param);
3344 /* JOIN sends FACILITY message */
3345 case MESSAGE_FACILITY:
3346 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);
3347 join_facility(portlist, message_type, param);
3350 /* JOIN sends OVERLAP message */
3351 case MESSAGE_OVERLAP:
3352 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);
3353 if (e_state!=EPOINT_STATE_IN_SETUP
3354 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3355 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3358 join_overlap(portlist, message_type, param);
3361 /* JOIN sends PROCEEDING message */
3362 case MESSAGE_PROCEEDING:
3363 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);
3364 if(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_proceeding(portlist, message_type, param);
3371 /* JOIN sends ALERTING message */
3372 case MESSAGE_ALERTING:
3373 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);
3374 if (e_state!=EPOINT_STATE_IN_OVERLAP
3375 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3376 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3379 join_alerting(portlist, message_type, param);
3382 /* JOIN sends CONNECT message */
3383 case MESSAGE_CONNECT:
3384 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);
3385 if (e_state!=EPOINT_STATE_IN_OVERLAP
3386 && e_state!=EPOINT_STATE_IN_PROCEEDING
3387 && e_state!=EPOINT_STATE_IN_ALERTING) {
3388 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3391 join_connect(portlist, message_type, param);
3394 /* JOIN sends DISCONNECT/RELEASE message */
3395 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3396 case MESSAGE_RELEASE: /* JOIN releases */
3397 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);
3398 join_disconnect_release(message_type, param);
3401 /* JOIN sends SETUP message */
3403 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);
3404 join_setup(portlist, message_type, param);
3407 /* JOIN sends special mISDNSIGNAL message */
3408 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3409 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);
3410 join_mISDNsignal(portlist, message_type, param);
3414 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3415 /* JOIN requests bchannel */
3416 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3417 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);
3418 /* only one port is expected to be connected to bchannel */
3425 set_tone(portlist, NULL);
3426 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3427 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3431 /* JOIN has pattern available */
3432 case MESSAGE_PATTERN: /* indicating pattern available */
3433 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);
3434 if (!e_join_pattern) {
3435 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3439 set_tone(portlist, NULL);
3440 portlist = portlist->next;
3442 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3443 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3444 message->param.audiopath = 1;
3445 message_put(message);
3449 /* JOIN has no pattern available */
3450 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3451 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);
3452 if (e_join_pattern) {
3453 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3455 /* disconnect our audio tx and rx */
3456 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3457 message->param.audiopath = 0;
3458 message_put(message);
3463 /* JOIN (dunno at the moment) */
3464 case MESSAGE_REMOTE_AUDIO:
3465 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);
3466 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3467 message->param.audiopath = param->channel;
3468 message_put(message);
3472 /* JOIN sends a notify message */
3473 case MESSAGE_NOTIFY:
3474 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);
3475 join_notify(portlist, message_type, param);
3478 /* JOIN wants keypad / dtmf */
3479 case MESSAGE_ENABLEKEYPAD:
3480 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);
3483 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3487 /* JOIN sends a DTMF message */
3489 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);
3490 join_dtmf(portlist, message_type, param);
3494 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);
3499 /* pick_join will connect the first incoming call found. the endpoint
3500 * will receivce a MESSAGE_CONNECT.
3502 int match_list(char *list, char *item)
3504 char *end, *next = NULL;
3506 /* no list make matching */
3511 /* eliminate white spaces */
3512 while (*list > '\0' && *list <= ' ')
3518 /* if end of list is reached, we return */
3519 if (list[0] == '\0')
3521 /* if we have more than one entry (left) */
3522 if ((end = strchr(list, ',')))
3525 next = end = strchr(list, '\0');
3526 while (*(end-1) <= ' ')
3528 /* if string part matches item */
3529 if (!strncmp(list, item, end-list))
3535 void EndpointAppPBX::pick_join(char *extensions)
3537 struct lcr_msg *message;
3538 struct port_list *portlist;
3540 class EndpointAppPBX *eapp, *found;
3542 class JoinPBX *joinpbx;
3543 struct join_relation *relation;
3546 /* find an endpoint that is ringing internally or vbox with higher priority */
3549 eapp = apppbx_first;
3551 if (eapp!=this && ea_endpoint->ep_portlist) {
3552 portlist = eapp->ea_endpoint->ep_portlist;
3554 if ((port = find_port_id(portlist->port_id))) {
3555 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3556 if (match_list(extensions, eapp->e_ext.number)) {
3562 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3563 && port->p_state==PORT_STATE_OUT_ALERTING)
3564 if (match_list(extensions, eapp->e_ext.number)) {
3568 portlist = portlist->next;
3576 /* if no endpoint found */
3578 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);
3580 set_tone(ea_endpoint->ep_portlist, "cause_10");
3581 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3582 new_state(EPOINT_STATE_OUT_DISCONNECT);
3587 if (ea_endpoint->ep_join_id) {
3588 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3591 if (!eapp->ea_endpoint->ep_join_id) {
3592 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3595 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3597 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3600 if (join->j_type != JOIN_TYPE_PBX) {
3601 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3604 joinpbx = (class JoinPBX *)join;
3605 relation = joinpbx->j_relation;
3607 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3610 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3611 relation = relation->next;
3613 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3618 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3620 if (options.deb & DEBUG_EPOINT) {
3621 class Join *debug_c = join_first;
3622 class Endpoint *debug_e = epoint_first;
3623 class Port *debug_p = port_first;
3625 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3627 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3629 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3630 debug_c = debug_c->next;
3632 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3634 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3635 debug_e = debug_e->next;
3637 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3639 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3640 debug_p = debug_p->next;
3645 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3646 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3647 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3649 /* connnecting our endpoint */
3650 new_state(EPOINT_STATE_CONNECT);
3651 if (e_ext.number[0])
3653 set_tone(ea_endpoint->ep_portlist, NULL);
3655 /* now we send a release to the ringing endpoint */
3656 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3657 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3658 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3659 message_put(message);
3661 /* we send a connect to the join with our caller id */
3662 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3663 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3664 message->param.connectinfo.present = e_callerinfo.present;
3665 message->param.connectinfo.screen = e_callerinfo.screen;
3666 message->param.connectinfo.itype = e_callerinfo.itype;
3667 message->param.connectinfo.ntype = e_callerinfo.ntype;
3668 message_put(message);
3670 /* we send a connect to our port with the remote callerid */
3671 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3672 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3673 message->param.connectinfo.present = eapp->e_callerinfo.present;
3674 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3675 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3676 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3677 /* handle restricted caller ids */
3678 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);
3679 /* display callerid if desired for extension */
3680 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));
3681 message_put(message);
3683 /* we send a connect to the audio path (not for vbox) */
3684 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3685 message->param.audiopath = 1;
3686 message_put(message);
3688 /* beeing paranoid, we make call update */
3689 trigger_work(&joinpbx->j_updatebridge);
3691 if (options.deb & DEBUG_EPOINT) {
3692 class Join *debug_c = join_first;
3693 class Endpoint *debug_e = epoint_first;
3694 class Port *debug_p = port_first;
3696 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3698 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3700 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3701 debug_c = debug_c->next;
3703 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3705 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3706 debug_e = debug_e->next;
3708 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3710 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3711 debug_p = debug_p->next;
3717 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3719 void EndpointAppPBX::join_join(void)
3721 struct lcr_msg *message;
3722 struct join_relation *our_relation, *other_relation;
3723 struct join_relation **our_relation_pointer, **other_relation_pointer;
3724 class Join *our_join, *other_join;
3725 class JoinPBX *our_joinpbx, *other_joinpbx;
3726 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3727 class Port *our_port, *other_port;
3728 class Pdss1 *our_pdss1, *other_pdss1;
3730 /* are we a candidate to join a join? */
3731 our_join = find_join_id(ea_endpoint->ep_join_id);
3733 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3736 if (our_join->j_type != JOIN_TYPE_PBX) {
3737 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3740 our_joinpbx = (class JoinPBX *)our_join;
3741 if (!ea_endpoint->ep_portlist) {
3742 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3745 if (!e_ext.number[0]) {
3746 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3749 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3751 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3754 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3755 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3758 our_pdss1 = (class Pdss1 *)our_port;
3760 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3761 other_eapp = apppbx_first;
3763 if (other_eapp == this) {
3764 other_eapp = other_eapp->next;
3767 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);
3768 if (other_eapp->e_ext.number[0] /* has terminal */
3769 && other_eapp->ea_endpoint->ep_portlist /* has port */
3770 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3771 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3772 if (other_port) { /* port still exists */
3773 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3774 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3775 other_pdss1 = (class Pdss1 *)other_port;
3776 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);
3777 if (other_pdss1->p_m_hold /* port is on hold */
3778 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3779 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3782 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3785 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3788 other_eapp = other_eapp->next;
3791 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3794 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3796 /* if we have the same join */
3797 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3798 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3801 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3803 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3806 if (other_join->j_type != JOIN_TYPE_PBX) {
3807 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3810 other_joinpbx = (class JoinPBX *)other_join;
3811 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3812 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3816 /* remove relation to endpoint for join on hold */
3817 other_relation = other_joinpbx->j_relation;
3818 other_relation_pointer = &other_joinpbx->j_relation;
3819 while(other_relation) {
3820 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3821 /* detach other endpoint on hold */
3822 *other_relation_pointer = other_relation->next;
3823 FREE(other_relation, sizeof(struct join_relation));
3825 other_relation = *other_relation_pointer;
3826 other_eapp->ea_endpoint->ep_join_id = 0;
3830 /* change join/hold pointer of endpoint to the new join */
3831 temp_epoint = find_epoint_id(other_relation->epoint_id);
3833 if (temp_epoint->ep_join_id == other_join->j_serial)
3834 temp_epoint->ep_join_id = our_join->j_serial;
3837 other_relation_pointer = &other_relation->next;
3838 other_relation = other_relation->next;
3840 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3842 /* join call relations */
3843 our_relation = our_joinpbx->j_relation;
3844 our_relation_pointer = &our_joinpbx->j_relation;
3845 while(our_relation) {
3846 our_relation_pointer = &our_relation->next;
3847 our_relation = our_relation->next;
3849 *our_relation_pointer = other_joinpbx->j_relation;
3850 other_joinpbx->j_relation = NULL;
3851 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3853 /* release endpoint on hold */
3854 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3855 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3856 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3857 message_put(message);
3859 /* if we are not a partyline, we get partyline state from other join */
3860 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3862 /* remove empty join */
3864 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3866 /* mixer must update */
3867 trigger_work(&our_joinpbx->j_updatebridge);
3869 /* we send a retrieve to that endpoint */
3870 // mixer will update the hold-state of the join and send it to the endpoints is changes
3874 /* check if we have an external call
3875 * this is used to check for encryption ability
3877 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3879 struct join_relation *relation;
3881 class JoinPBX *joinpbx;
3882 class Endpoint *epoint;
3884 /* some paranoia check */
3885 if (!ea_endpoint->ep_portlist) {
3886 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3887 *errstr = "No Call";
3890 if (!e_ext.number[0]) {
3891 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3892 *errstr = "No Call";
3896 /* check if we have a join with 2 parties */
3897 join = find_join_id(ea_endpoint->ep_join_id);
3899 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3900 *errstr = "No Call";
3903 if (join->j_type != JOIN_TYPE_PBX) {
3904 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3905 *errstr = "No PBX Call";
3908 joinpbx = (class JoinPBX *)join;
3909 relation = joinpbx->j_relation;
3911 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3912 *errstr = "No Call";
3915 if (!relation->next) {
3916 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3917 *errstr = "No Call";
3920 if (relation->next->next) {
3921 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3922 *errstr = "Err: Conference";
3925 if (relation->epoint_id == ea_endpoint->ep_serial) {
3926 relation = relation->next;
3927 if (relation->epoint_id == ea_endpoint->ep_serial) {
3928 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3929 *errstr = "Software Error";
3934 /* check remote port for external call */
3935 epoint = find_epoint_id(relation->epoint_id);
3937 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3938 *errstr = "No Call";
3941 if (!epoint->ep_portlist) {
3942 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3943 *errstr = "No Call";
3946 *port = find_port_id(epoint->ep_portlist->port_id);
3948 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3949 *errstr = "No Call";
3952 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
3953 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3954 *errstr = "No Ext Call";
3957 if ((*port)->p_state != PORT_STATE_CONNECT) {
3958 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3959 *errstr = "No Ext Connect";
3965 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3967 const char *logtext = "unknown";
3970 switch(message_type) {
3972 trace_header("SETUP", dir);
3973 if (dir == DIRECTION_OUT)
3974 add_trace("to", NULL, "CH(%lu)", port_id);
3975 if (dir == DIRECTION_IN)
3976 add_trace("from", NULL, "CH(%lu)", port_id);
3977 if (param->setup.callerinfo.extension[0])
3978 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3979 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3980 switch(param->setup.callerinfo.present) {
3981 case INFO_PRESENT_RESTRICTED:
3982 add_trace("caller id", "present", "restricted");
3984 case INFO_PRESENT_ALLOWED:
3985 add_trace("caller id", "present", "allowed");
3988 add_trace("caller id", "present", "not available");
3990 if (param->setup.callerinfo.ntype2) {
3991 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3992 switch(param->setup.callerinfo.present) {
3993 case INFO_PRESENT_RESTRICTED:
3994 add_trace("caller id2", "present", "restricted");
3996 case INFO_PRESENT_ALLOWED:
3997 add_trace("caller id2", "present", "allowed");
4000 add_trace("caller id2", "present", "not available");
4003 if (param->setup.redirinfo.id[0]) {
4004 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4005 switch(param->setup.redirinfo.present) {
4006 case INFO_PRESENT_RESTRICTED:
4007 add_trace("redir'ing", "present", "restricted");
4009 case INFO_PRESENT_ALLOWED:
4010 add_trace("redir'ing", "present", "allowed");
4013 add_trace("redir'ing", "present", "not available");
4016 if (param->setup.dialinginfo.id[0])
4017 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4018 if (param->setup.dialinginfo.keypad[0])
4019 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4020 if (param->setup.dialinginfo.display[0])
4021 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4022 if (param->setup.dialinginfo.sending_complete)
4023 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4027 case MESSAGE_OVERLAP:
4028 trace_header("SETUP ACKNOWLEDGE", dir);
4029 if (dir == DIRECTION_OUT)
4030 add_trace("to", NULL, "CH(%lu)", port_id);
4031 if (dir == DIRECTION_IN)
4032 add_trace("from", NULL, "CH(%lu)", port_id);
4036 case MESSAGE_PROCEEDING:
4037 trace_header("PROCEEDING", dir);
4038 if (dir == DIRECTION_OUT)
4039 add_trace("to", NULL, "CH(%lu)", port_id);
4040 if (dir == DIRECTION_IN)
4041 add_trace("from", NULL, "CH(%lu)", port_id);
4045 case MESSAGE_ALERTING:
4046 trace_header("ALERTING", dir);
4047 if (dir == DIRECTION_OUT)
4048 add_trace("to", NULL, "CH(%lu)", port_id);
4049 if (dir == DIRECTION_IN)
4050 add_trace("from", NULL, "CH(%lu)", port_id);
4054 case MESSAGE_CONNECT:
4055 trace_header("CONNECT", dir);
4056 if (dir == DIRECTION_OUT)
4057 add_trace("to", NULL, "CH(%lu)", port_id);
4058 if (dir == DIRECTION_IN)
4059 add_trace("from", NULL, "CH(%lu)", port_id);
4060 if (param->connectinfo.extension[0])
4061 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4062 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4063 switch(param->connectinfo.present) {
4064 case INFO_PRESENT_RESTRICTED:
4065 add_trace("connect id", "present", "restricted");
4067 case INFO_PRESENT_ALLOWED:
4068 add_trace("connect id", "present", "allowed");
4071 add_trace("connect id", "present", "not available");
4073 if (param->connectinfo.display[0])
4074 add_trace("display", NULL, "%s", param->connectinfo.display);
4078 case MESSAGE_DISCONNECT:
4079 case MESSAGE_RELEASE:
4080 if (message_type == MESSAGE_DISCONNECT)
4081 trace_header("DISCONNECT", dir);
4083 trace_header("RELEASE", dir);
4084 if (dir == DIRECTION_OUT)
4085 add_trace("to", NULL, "CH(%lu)", port_id);
4086 if (dir == DIRECTION_IN)
4087 add_trace("from", NULL, "CH(%lu)", port_id);
4088 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4089 switch(param->disconnectinfo.location) {
4091 add_trace("cause", "location", "0-User");
4093 case LOCATION_PRIVATE_LOCAL:
4094 add_trace("cause", "location", "1-Local-PBX");
4096 case LOCATION_PUBLIC_LOCAL:
4097 add_trace("cause", "location", "2-Local-Exchange");
4099 case LOCATION_TRANSIT:
4100 add_trace("cause", "location", "3-Transit");
4102 case LOCATION_PUBLIC_REMOTE:
4103 add_trace("cause", "location", "4-Remote-Exchange");
4105 case LOCATION_PRIVATE_REMOTE:
4106 add_trace("cause", "location", "5-Remote-PBX");
4108 case LOCATION_INTERNATIONAL:
4109 add_trace("cause", "location", "7-International-Exchange");
4111 case LOCATION_BEYOND:
4112 add_trace("cause", "location", "10-Beyond-Interworking");
4115 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4117 if (param->disconnectinfo.display[0])
4118 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4122 case MESSAGE_NOTIFY:
4123 switch(param->notifyinfo.notify) {
4128 logtext = "USER_SUSPENDED";
4131 logtext = "BEARER_SERVICE_CHANGED";
4134 logtext = "USER_RESUMED";
4137 logtext = "CONFERENCE_ESTABLISHED";
4140 logtext = "CONFERENCE_DISCONNECTED";
4143 logtext = "OTHER_PARTY_ADDED";
4146 logtext = "ISOLATED";
4149 logtext = "REATTACHED";
4152 logtext = "OTHER_PARTY_ISOLATED";
4155 logtext = "OTHER_PARTY_REATTACHED";
4158 logtext = "OTHER_PARTY_SPLIT";
4161 logtext = "OTHER_PARTY_DISCONNECTED";
4164 logtext = "CONFERENCE_FLOATING";
4167 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4170 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4173 logtext = "CALL_IS_A_WAITING_CALL";
4176 logtext = "DIVERSION_ACTIVATED";
4179 logtext = "RESERVED_CT_1";
4182 logtext = "RESERVED_CT_2";
4185 logtext = "REVERSE_CHARGING";
4188 logtext = "REMOTE_HOLD";
4191 logtext = "REMOTE_RETRIEVAL";
4194 logtext = "CALL_IS_DIVERTING";
4197 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4201 trace_header("NOTIFY", dir);
4202 if (dir == DIRECTION_OUT)
4203 add_trace("to", NULL, "CH(%lu)", port_id);
4204 if (dir == DIRECTION_IN)
4205 add_trace("from", NULL, "CH(%lu)", port_id);
4206 if (param->notifyinfo.notify)
4207 add_trace("indicator", NULL, "%s", logtext);
4208 if (param->notifyinfo.id[0]) {
4209 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4210 switch(param->notifyinfo.present) {
4211 case INFO_PRESENT_RESTRICTED:
4212 add_trace("redir'on", "present", "restricted");
4214 case INFO_PRESENT_ALLOWED:
4215 add_trace("redir'on", "present", "allowed");
4218 add_trace("redir'on", "present", "not available");
4221 if (param->notifyinfo.display[0])
4222 add_trace("display", NULL, "%s", param->notifyinfo.display);
4226 case MESSAGE_PROGRESS:
4227 switch(param->progressinfo.progress) {
4229 logtext = "Call is not end to end ISDN";
4232 logtext = "Destination address is non-ISDN";
4235 logtext = "Origination address is non-ISDN";
4238 logtext = "Call has returned to the ISDN";
4241 logtext = "In-band info or pattern available";
4244 SPRINT(buffer, "%d", param->progressinfo.progress);
4248 trace_header("PROGRESS", dir);
4249 if (dir == DIRECTION_OUT)
4250 add_trace("to", NULL, "CH(%lu)", port_id);
4251 if (dir == DIRECTION_IN)
4252 add_trace("from", NULL, "CH(%lu)", port_id);
4253 add_trace("indicator", NULL, "%s", logtext);
4254 switch(param->progressinfo.location) {
4256 add_trace("cause", "location", "0-User");
4258 case LOCATION_PRIVATE_LOCAL:
4259 add_trace("cause", "location", "1-Local-PBX");
4261 case LOCATION_PUBLIC_LOCAL:
4262 add_trace("cause", "location", "2-Local-Exchange");
4264 case LOCATION_TRANSIT:
4265 add_trace("cause", "location", "3-Transit");
4267 case LOCATION_PUBLIC_REMOTE:
4268 add_trace("cause", "location", "4-Remote-Exchange");
4270 case LOCATION_PRIVATE_REMOTE:
4271 add_trace("cause", "location", "5-Remote-PBX");
4273 case LOCATION_INTERNATIONAL:
4274 add_trace("cause", "location", "7-International-Exchange");
4276 case LOCATION_BEYOND:
4277 add_trace("cause", "location", "10-Beyond-Interworking");
4280 add_trace("cause", "location", "%d", param->progressinfo.location);
4285 case MESSAGE_INFORMATION:
4286 trace_header("INFORMATION", dir);
4287 if (dir == DIRECTION_OUT)
4288 add_trace("to", NULL, "CH(%lu)", port_id);
4289 if (dir == DIRECTION_IN)
4290 add_trace("from", NULL, "CH(%lu)", port_id);
4291 if (param->information.id[0])
4292 add_trace("dialing", NULL, "%s", param->information.id);
4293 if (param->information.display[0])
4294 add_trace("display", NULL, "%s", param->information.display);
4295 if (param->information.sending_complete)
4296 add_trace("complete", NULL, "true", param->information.sending_complete);
4300 case MESSAGE_FACILITY:
4301 trace_header("FACILITY", dir);
4302 if (dir == DIRECTION_OUT)
4303 add_trace("to", NULL, "CH(%lu)", port_id);
4304 if (dir == DIRECTION_IN)
4305 add_trace("from", NULL, "CH(%lu)", port_id);
4310 trace_header("TONE", dir);
4311 if (dir == DIRECTION_OUT)
4312 add_trace("to", NULL, "CH(%lu)", port_id);
4313 if (dir == DIRECTION_IN)
4314 add_trace("from", NULL, "CH(%lu)", port_id);
4315 if (param->tone.name[0]) {
4316 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4317 add_trace("name", NULL, "%s", param->tone.name);
4319 add_trace("off", NULL, NULL);
4323 case MESSAGE_SUSPEND:
4324 case MESSAGE_RESUME:
4325 if (message_type == MESSAGE_SUSPEND)
4326 trace_header("SUSPEND", dir);
4328 trace_header("RESUME", dir);
4329 if (dir == DIRECTION_OUT)
4330 add_trace("to", NULL, "CH(%lu)", port_id);
4331 if (dir == DIRECTION_IN)
4332 add_trace("from", NULL, "CH(%lu)", port_id);
4333 if (param->parkinfo.len)
4334 add_trace("length", NULL, "%d", param->parkinfo.len);
4339 case MESSAGE_BCHANNEL:
4340 trace_header("BCHANNEL", dir);
4341 switch(param->bchannel.type) {
4342 case BCHANNEL_REQUEST:
4343 add_trace("type", NULL, "request");
4345 case BCHANNEL_ASSIGN:
4346 add_trace("type", NULL, "assign");
4348 case BCHANNEL_ASSIGN_ACK:
4349 add_trace("type", NULL, "assign_ack");
4351 case BCHANNEL_REMOVE:
4352 add_trace("type", NULL, "remove");
4354 case BCHANNEL_REMOVE_ACK:
4355 add_trace("type", NULL, "remove_ack");
4358 if (param->bchannel.addr)
4359 add_trace("address", NULL, "%x", param->bchannel.addr);
4365 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4369 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4371 struct lcr_msg *message;
4375 if (!portlist->port_id)
4378 if (!e_connectedmode) {
4379 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4380 message->param.disconnectinfo.cause = cause;
4381 message->param.disconnectinfo.location = location;
4383 SCPY(message->param.disconnectinfo.display, display);
4385 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4387 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4389 SCPY(message->param.notifyinfo.display, display);
4391 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4393 message_put(message);
4394 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);