1 /*****************************************************************************\
3 ** Linux Call Router **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** The EndpointAppPBX implements PBX4Linux **
10 \*****************************************************************************/
15 class EndpointAppPBX *apppbx_first = NULL;
17 int action_timeout(struct lcr_timer *timer, void *instance, int index);
18 int match_timeout(struct lcr_timer *timer, void *instance, int index);
19 int redial_timeout(struct lcr_timer *timer, void *instance, int index);
20 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index);
21 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index);
22 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index);
23 int password_timeout(struct lcr_timer *timer, void *instance, int index);
24 int callback_timeout(struct lcr_timer *timer, void *instance, int index);
27 * EndpointAppPBX constructor
29 EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin)
31 class EndpointAppPBX **apppointer;
33 memset(&e_crypt_handler, 0, sizeof(e_crypt_handler));
34 add_timer(&e_crypt_handler, crypt_handler, this, 0);
35 memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh));
36 add_timer(&e_vbox_refresh, vbox_refresh, this, 0);
37 memset(&e_action_timeout, 0, sizeof(e_action_timeout));
38 add_timer(&e_action_timeout, action_timeout, this, 0);
39 memset(&e_match_timeout, 0, sizeof(e_match_timeout));
40 add_timer(&e_match_timeout, match_timeout, this, 0);
41 memset(&e_redial_timeout, 0, sizeof(e_redial_timeout));
42 add_timer(&e_redial_timeout, redial_timeout, this, 0);
43 memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout));
44 add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0);
45 memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout));
46 add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0);
47 memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout));
48 add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0);
49 memset(&e_callback_timeout, 0, sizeof(e_callback_timeout));
50 add_timer(&e_callback_timeout, callback_timeout, this, 0);
51 memset(&e_password_timeout, 0, sizeof(e_password_timeout));
52 add_timer(&e_password_timeout, password_timeout, this, 0);
55 /* add application to chain */
57 apppointer = &apppbx_first;
59 apppointer = &((*apppointer)->next);
63 memset(&e_ext, 0, sizeof(struct extension));
64 // *************** NOTE: also change value in read_extension() **************
65 e_ext.rights = 4; /* international */
66 e_ext.rx_gain = e_ext.tx_gain = 0;
67 e_state = EPOINT_STATE_IDLE;
68 e_ext.number[0] = '\0';
69 e_extension_interface[0] = '\0';
70 memset(&e_callerinfo, 0, sizeof(struct caller_info));
71 memset(&e_dialinginfo, 0, sizeof(struct dialing_info));
72 memset(&e_connectinfo, 0, sizeof(struct connect_info));
73 memset(&e_redirinfo, 0, sizeof(struct redir_info));
74 memset(&e_capainfo, 0, sizeof(struct capa_info));
77 e_ruleset = ruleset_main;
79 e_rule = e_ruleset->rule_first;
82 e_match_to_action = NULL;
84 e_extdialing = e_dialinginfo.id;
88 // e_join_tone[0] = e_hold_tone[0] = '\0';
89 e_join_pattern /*= e_hold_pattern*/ = 0;
91 e_adminid = 0; // will be set, if call was initiated via admin socket
94 e_cbdialing[0] = '\0';
97 memset(&e_callbackinfo, 0, sizeof(struct caller_info));
103 e_multipoint_cause = 0;
104 e_multipoint_location = 0;
105 e_dialing_queue[0] = '\0';
107 e_crypt_state = CM_ST_NULL;
108 e_crypt_keyengine_busy = 0;
109 e_crypt_info[0] = '\0';
112 e_tx_state = NOTIFY_STATE_ACTIVE;
113 e_rx_state = NOTIFY_STATE_ACTIVE;
114 e_join_cause = e_join_location = 0;
115 /*********************************
116 *********************************
117 ********* ATTENTION *************
118 *********************************
119 *********************************/
120 /* if you add new values, that must be initialized, also check if they must
121 * be initialized when doing callback
127 * EpointAppPBX destructor
129 EndpointAppPBX::~EndpointAppPBX(void)
131 class EndpointAppPBX *temp, **tempp;
133 del_timer(&e_crypt_handler);
134 del_timer(&e_vbox_refresh);
135 del_timer(&e_action_timeout);
136 del_timer(&e_match_timeout);
137 del_timer(&e_redial_timeout);
138 del_timer(&e_powerdial_timeout);
139 del_timer(&e_cfnr_timeout);
140 del_timer(&e_cfnr_call_timeout);
141 del_timer(&e_callback_timeout);
142 del_timer(&e_password_timeout);
146 tempp = &apppbx_first;
155 FATAL("Endpoint not in endpoint's list.\n");
162 * trace header for application
164 void EndpointAppPBX::trace_header(const char *name, int direction)
168 char msgtext[sizeof(_trace.name)];
172 /* init trace with given values */
175 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
179 ea_endpoint->ep_serial,
186 /* set new endpoint state
188 void EndpointAppPBX::new_state(int state)
191 if (e_state != state) {
192 trace_header("NEW STATE", DIRECTION_NONE);
193 add_trace("state", "old", "%s", state_name[e_state]);
194 add_trace("state", "new", "%s", state_name[state]);
202 /* release join and port (as specified)
204 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force)
206 struct port_list *portlist;
207 struct lcr_msg *message;
210 /* message to test call */
211 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
213 /* if a release is pending */
214 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
215 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
216 if (ea_endpoint->ep_join_id) {
217 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
218 message->param.disconnectinfo.cause = joincause;
219 message->param.disconnectinfo.location = joinlocation;
220 message_put(message);
221 ea_endpoint->ep_join_id = 0;
225 if (release != RELEASE_PORT_JOINONLY) {
227 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
232 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
233 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
234 while((portlist = ea_endpoint->ep_portlist)) {
235 if (portlist->port_id) {
236 SPRINT(cause, "cause_%02x", portcause);
237 set_tone(portlist, cause);
238 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
239 message->param.disconnectinfo.cause = portcause;
240 message->param.disconnectinfo.location = portlocation;
241 message->param.disconnectinfo.force = force; // set, if port should release imediately
242 message_put(message);
243 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
245 ea_endpoint->free_portlist(portlist);
248 /* if callback is enabled, call back with the given caller id */
249 if (e_callback_timeout.active) {
250 /* reset some stuff */
251 new_state(EPOINT_STATE_IDLE);
252 memset(&e_connectinfo, 0, sizeof(struct connect_info));
253 memset(&e_redirinfo, 0, sizeof(struct redir_info));
254 e_start = e_stop = 0;
255 e_ruleset = ruleset_main;
257 e_rule = e_ruleset->rule_first;
259 unsched_timer(&e_action_timeout);
260 unsched_timer(&e_match_timeout);
261 unsched_timer(&e_cfnr_timeout);
262 unsched_timer(&e_cfnr_call_timeout);
263 e_match_to_action = NULL;
265 e_extdialing = e_dialinginfo.id;
271 e_multipoint_cause = 0;
272 e_multipoint_location = 0;
273 e_dialing_queue[0] = '\0';
275 e_crypt_state = CM_ST_NULL;
276 e_crypt_keyengine_busy = 0;
277 e_crypt_info[0] = '\0';
281 e_tx_state = NOTIFY_STATE_ACTIVE;
282 e_rx_state = NOTIFY_STATE_ACTIVE;
283 e_join_cause = e_join_location = 0;
285 /* the caller info of the callback user */
286 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
287 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
288 /* create dialing by callerinfo */
289 if (e_ext.number[0] && e_extension_interface[0]) {
290 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
291 /* create callback to the current terminal */
292 SCPY(e_dialinginfo.id, e_ext.number);
293 SCPY(e_dialinginfo.interfaces, e_extension_interface);
294 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
295 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
298 SCPY(e_dialinginfo.id, e_cbto);
300 /* numberrize caller id and use it to dial to the callback */
301 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
303 e_dialinginfo.itype = INFO_ITYPE_ISDN;
304 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
305 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
310 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
311 if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */
312 trigger_work(&ea_endpoint->ep_delete);
318 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
319 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
321 PDEBUG(DEBUG_EPOINT, "id='%s' ntype=%d present=%d screen=%d extension='%s' name='%s'\n", (id)?id:"NULL", (ntype)?*ntype:-1, (present)?*present:-1, (screen)?*screen:-1, (extension)?extension:"NULL", (name)?name:"NULL");
323 /* caller id is not restricted, so we do nothing */
324 if (*present != INFO_PRESENT_RESTRICTED)
327 /* only extensions are restricted */
331 /* if we enabled anonymouse ignore */
332 if (ext->anon_ignore)
335 /* else we remove the caller id */
339 *ntype = INFO_NTYPE_UNKNOWN;
341 // *screen = INFO_SCREEN_USER;
342 // maybe we should not make voip address anonymous
345 // maybe it's no fraud to present extension id
347 // extension[0] = '\0';
352 /* used display message to display callerid as available */
353 char *EndpointAppPBX::apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name)
355 static char display[81];
358 const char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
360 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) id='%s' itype=%d ntype=%d present=%d screen=%d extension='%s' name='%s'\n", ea_endpoint->ep_serial, (id)?id:"NULL", itype, ntype, present, screen, (extension)?extension:"NULL", (name)?name:"NULL");
369 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
371 /* internal extension's caller id */
372 if (extension[0] && e_ext.display_int) {
374 SCAT(display, extension);
377 if (itype == INFO_ITYPE_VBOX)
378 SCAT(display, "(vbox)");
380 SCAT(display, "(int)");
383 /* external caller id */
384 if (!extension[0] && e_ext.display_ext) {
387 if (present == INFO_PRESENT_RESTRICTED)
388 SCAT(display, "anonymous");
390 SCAT(display, "unknown");
397 /* display if callerid is anonymouse but available due anon-ignore */
398 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED) {
400 SCAT(display, "unknown");
403 SCAT(display, " anon");
406 /* display if callerid is anonymouse but available due anon-ignore */
407 if (e_ext.display_fake && screen==INFO_SCREEN_USER && ntype!=INFO_NTYPE_NOTPRESENT) {
410 if (present == INFO_PRESENT_RESTRICTED)
411 SCAT(display, "anonymous");
413 SCAT(display, "unknown");
418 SCAT(display, " fake");
422 if (name[0] && e_ext.display_name) {
423 if (!display[0] && cid[0])
434 * uses the current state to notify activity
436 void EndpointAppPBX::notify_active(void)
438 struct port_list *portlist = ea_endpoint->ep_portlist;
439 struct lcr_msg *message;
443 case NOTIFY_STATE_ACTIVE:
444 /* we are already active, so we don't do anything */
447 case NOTIFY_STATE_SUSPEND:
448 notify = INFO_NOTIFY_USER_RESUMED;
450 set_tone(portlist, NULL);
451 portlist = portlist->next;
453 portlist = ea_endpoint->ep_portlist;
456 case NOTIFY_STATE_HOLD:
457 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
459 set_tone(portlist, NULL);
460 portlist = portlist->next;
462 portlist = ea_endpoint->ep_portlist;
465 case NOTIFY_STATE_CONFERENCE:
466 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
468 set_tone(portlist, NULL);
469 portlist = portlist->next;
471 portlist = ea_endpoint->ep_portlist;
475 PERROR("unknown e_tx_state = %d\n", e_tx_state);
480 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
481 message->param.notifyinfo.notify = notify;
482 message_put(message);
483 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
484 portlist = portlist->next;
490 * keypad functions during call. one example to use this is to put a call on hold or start a conference
492 void EndpointAppPBX::keypad_function(char digit)
495 /* we must be in a call, in order to send messages to the call */
496 if (e_ext.number[0] == '\0') {
497 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
502 /* join conference */
504 if (ea_endpoint->ep_join_id == 0) {
505 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
508 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
514 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
518 /* crypt key-exchange */
520 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
526 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
531 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
536 /* set tone pattern for port */
537 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
539 struct lcr_msg *message;
544 /* store for suspended processes */
548 if (e_join_pattern /* pattern are provided */
549 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
550 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
551 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
552 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
553 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
554 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
555 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
556 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
557 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
558 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
559 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
560 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
565 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
566 SCPY(message->param.tone.dir, e_ext.tones_dir);
567 SCPY(message->param.tone.name, tone);
568 message_put(message);
569 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
571 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
578 * hunts an mISDNport that is available for an outgoing call
579 * if no ifname was given, any interface that is not an extension
582 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
584 struct interface *interface;
585 struct interface_port *ifport, *ifport_start;
586 struct select_channel *selchannel;
587 struct mISDNport *mISDNport;
589 int there_is_an_external = 0;
591 interface = interface_first;
593 /* first find the given interface or, if not given, one with no extension */
596 if (!there_is_an_external && !(ifname && ifname[0])) {
597 trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
598 add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
604 /* check for given interface */
605 if (ifname && ifname[0]) {
606 if (!strcasecmp(interface->name, ifname)) {
607 /* found explicit interface */
608 trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
609 add_trace("interface", NULL, "%s", ifname);
615 if (interface->external) {
616 there_is_an_external = 1;
617 /* found non extension */
618 trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
619 add_trace("interface", NULL, "%s", interface->name);
625 interface = interface->next;
629 /* see if interface has ports */
630 if (!interface->ifport) {
632 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
633 add_trace("interface", NULL, "%s", interface->name);
635 interface = interface->next;
639 /* select port by algorithm */
640 ifport_start = interface->ifport;
642 if (interface->hunt == HUNT_ROUNDROBIN) {
643 while(ifport_start->next && index<interface->hunt_next) {
644 ifport_start = ifport_start->next;
647 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
648 add_trace("port", NULL, "%d", ifport_start->portnum);
649 add_trace("position", NULL, "%d", index);
654 ifport = ifport_start;
657 /* see if port is available */
658 if (!ifport->mISDNport) {
659 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
660 add_trace("port", NULL, "%d", ifport->portnum);
661 add_trace("position", NULL, "%d", index);
665 mISDNport = ifport->mISDNport;
667 /* see if port is administratively blocked */
669 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
670 add_trace("port", NULL, "%d", ifport->portnum);
671 add_trace("position", NULL, "%d", index);
676 /* see if link is up on PTP*/
677 if (mISDNport->l2hold && mISDNport->l2link<1) {
678 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
679 add_trace("port", NULL, "%d", ifport->portnum);
680 add_trace("position", NULL, "%d", index);
685 /* check for channel form selection list */
688 if (mISDNport->ss5) {
690 port = ss5_hunt_line(mISDNport);
692 *channel = port->p_m_b_channel;
693 trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
694 add_trace("port", NULL, "%d", ifport->portnum);
695 add_trace("position", NULL, "%d", index);
696 add_trace("channel", NULL, "%d", *channel);
702 selchannel = ifport->out_channel;
704 switch(selchannel->channel) {
705 case CHANNEL_FREE: /* free channel */
706 if (mISDNport->b_reserved >= mISDNport->b_num)
707 break; /* all channel in use or reserverd */
710 while(i < mISDNport->b_num) {
711 if (mISDNport->b_port[i] == NULL) {
712 *channel = i+1+(i>=15);
713 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
714 add_trace("port", NULL, "%d", ifport->portnum);
715 add_trace("position", NULL, "%d", index);
716 add_trace("channel", NULL, "%d", *channel);
724 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
725 add_trace("port", NULL, "%d", ifport->portnum);
726 add_trace("position", NULL, "%d", index);
730 case CHANNEL_ANY: /* don't ask for channel */
731 if (mISDNport->b_reserved >= mISDNport->b_num) {
732 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
733 add_trace("port", NULL, "%d", ifport->portnum);
734 add_trace("position", NULL, "%d", index);
735 add_trace("total", NULL, "%d", mISDNport->b_num);
736 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
738 break; /* all channel in use or reserverd */
740 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
741 add_trace("port", NULL, "%d", ifport->portnum);
742 add_trace("position", NULL, "%d", index);
744 *channel = CHANNEL_ANY;
747 case CHANNEL_NO: /* call waiting */
748 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
749 add_trace("port", NULL, "%d", ifport->portnum);
750 add_trace("position", NULL, "%d", index);
752 *channel = CHANNEL_NO;
756 if (selchannel->channel<1 || selchannel->channel==16) {
757 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
758 add_trace("port", NULL, "%d", ifport->portnum);
759 add_trace("position", NULL, "%d", index);
760 add_trace("channel", NULL, "%d", selchannel->channel);
762 break; /* invalid channels */
764 i = selchannel->channel-1-(selchannel->channel>=17);
765 if (i >= mISDNport->b_num) {
766 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
767 add_trace("port", NULL, "%d", ifport->portnum);
768 add_trace("position", NULL, "%d", index);
769 add_trace("channel", NULL, "%d", selchannel->channel);
770 add_trace("channels", NULL, "%d", mISDNport->b_num);
772 break; /* channel not in port */
774 if (mISDNport->b_port[i] == NULL) {
775 *channel = selchannel->channel;
776 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
777 add_trace("port", NULL, "%d", ifport->portnum);
778 add_trace("position", NULL, "%d", index);
779 add_trace("channel", NULL, "%d", *channel);
786 break; /* found channel */
787 selchannel = selchannel->next;
791 /* if channel was found, return mISDNport and channel */
793 /* setting next port to start next time */
794 if (interface->hunt == HUNT_ROUNDROBIN) {
798 interface->hunt_next = index;
804 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
805 add_trace("port", NULL, "%d", ifport->portnum);
806 add_trace("position", NULL, "%d", index);
810 /* go next port, until all ports are checked */
812 ifport = ifport->next;
815 ifport = interface->ifport;
817 if (ifport != ifport_start)
821 interface = interface->next;
825 return(NULL); /* no port found */
828 /* outgoing setup to port(s)
829 * ports will be created and a setup is sent if everything is ok. otherwhise
830 * the endpoint is destroyed.
832 void EndpointAppPBX::out_setup(int cfnr)
834 struct dialing_info dialinginfo;
836 struct port_list *portlist;
837 struct lcr_msg *message;
839 int cause = CAUSE_RESSOURCEUNAVAIL;
842 struct mISDNport *mISDNport;
845 class EndpointAppPBX *atemp;
846 // char allowed_ports[256];
848 char ifname[sizeof(e_ext.interfaces)],
850 struct port_settings port_settings;
853 int mode = B_MODE_TRANSPARENT;
854 struct admin_list *admin;
856 /* set bchannel mode */
857 mode = e_capainfo.source_mode;
859 /* create settings for creating port */
860 memset(&port_settings, 0, sizeof(port_settings));
862 SCPY(port_settings.tones_dir, e_ext.tones_dir);
864 SCPY(port_settings.tones_dir, options.tones_dir);
865 port_settings.no_seconds = e_ext.no_seconds;
867 /* NOTE: currently the try_card feature is not supported. it should be used later to try another card, if the outgoing call fails on one port */
869 /* check what dialinginfo.itype we got */
870 switch(e_dialinginfo.itype) {
871 /* *********************** call to extension or vbox */
872 case INFO_ITYPE_ISDN_EXTENSION:
873 /* check if we deny incoming calls when we use an extension */
874 if (e_ext.noknocking) {
875 atemp = apppbx_first;
878 if (!strcmp(atemp->e_ext.number, e_ext.number))
883 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
884 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
885 return; /* must exit here */
888 /* FALL THROUGH !!!! */
889 case INFO_ITYPE_VBOX:
890 /* get dialed extension's info */
891 // SCPY(exten, e_dialinginfo.id);
892 // if (strchr(exten, ','))
893 // *strchr(exten, ',') = '\0';
894 // if (!read_extension(&e_ext, exten))
895 if (!read_extension(&e_ext, e_dialinginfo.id)) {
896 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
897 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
898 return; /* must exit here */
900 e_dialinginfo.sending_complete = 1;
902 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
903 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
908 /* string from unconditional call forward (cfu) */
911 /* present to forwarded party */
912 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
913 e_callerinfo.present = INFO_PRESENT_ALLOWED;
915 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
919 /* string from busy call forward (cfb) */
922 class EndpointAppPBX *checkapp = apppbx_first;
924 if (checkapp != this) { /* any other endpoint except our own */
925 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
926 /* present to forwarded party */
927 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
928 e_callerinfo.present = INFO_PRESENT_ALLOWED;
930 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
934 checkapp = checkapp->next;
938 /* string from no-response call forward (cfnr) */
941 /* when cfnr is done, out_setup() will setup the call */
943 /* present to forwarded party */
944 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
945 e_callerinfo.present = INFO_PRESENT_ALLOWED;
949 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
950 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
951 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
952 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) setting time for call-forward-busy to %s with delay %ld.\n", ea_endpoint->ep_serial, e_ext.cfnr, e_ext.cfnr_delay);
956 /* call to all internal interfaces */
957 p = e_ext.interfaces;
958 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
961 while(*p!=',' && *p!='\0')
966 /* found interface */
967 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
968 /* hunt for mISDNport and create Port */
969 mISDNport = hunt_port(ifname, &channel);
971 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
972 add_trace("interface", NULL, "%s", ifname);
976 /* creating INTERNAL port */
977 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
980 port = ss5_hunt_line(mISDNport);
984 if (mISDNport->gsm_bs)
985 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
989 if (mISDNport->gsm_ms)
990 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
994 if (mISDNport->ifport->interface->sip)
995 port = new Psip(PORT_TYPE_SIP_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, mISDNport->ifport->interface);
998 if (mISDNport->ifport->remote) {
1001 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1003 admin = admin->next;
1006 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1007 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1011 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1013 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1015 FATAL("Failed to create Port instance\n");
1016 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
1017 memset(&dialinginfo, 0, sizeof(dialinginfo));
1018 SCPY(dialinginfo.id, e_dialinginfo.id);
1019 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1020 dialinginfo.ntype = e_dialinginfo.ntype;
1021 /* create port_list relation */
1022 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1024 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1026 goto check_anycall_intern;
1028 /* directory.list */
1029 if (e_callerinfo.id[0] && e_ext.display_name) {
1030 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1032 SCPY(e_callerinfo.name, dirname);
1034 // dss1 = (class Pdss1 *)port;
1036 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1037 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1038 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1039 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1040 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1041 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1042 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1043 //terminal if (e_dialinginfo.id)
1044 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1045 /* handle restricted caller ids */
1046 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1047 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1048 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1049 /* display callerid if desired for extension */
1050 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
1051 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1052 /* use cnip, if enabld */
1053 // if (!e_ext.centrex)
1054 // message->param.setup.callerinfo.name[0] = '\0';
1055 /* screen clip if prefix is required */
1056 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1057 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1058 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1059 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1061 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1062 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1063 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1064 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1066 /* use internal caller id */
1067 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1068 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1069 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1070 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1072 message_put(message);
1073 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1077 /* string from parallel call forward (cfp) */
1080 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1081 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1082 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1086 vbox_only: /* entry point for answering machine only */
1087 cfu_only: /* entry point for cfu */
1088 cfb_only: /* entry point for cfb */
1089 cfnr_only: /* entry point for cfnr */
1090 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1094 /* only if vbox should be dialed, and terminal is given */
1095 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1096 /* go to the end of p */
1099 /* answering vbox call */
1100 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1102 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1103 FATAL("No memory for VBOX Port instance\n");
1104 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1105 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1108 while(*p!=',' && *p!='\0')
1113 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1114 /* hunt for mISDNport and create Port */
1115 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1117 /* creating EXTERNAL port*/
1118 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1121 port = ss5_hunt_line(mISDNport);
1124 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1126 FATAL("No memory for Port instance\n");
1127 earlyb = mISDNport->earlyb;
1130 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1131 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1136 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1137 goto check_anycall_intern;
1139 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1140 memset(&dialinginfo, 0, sizeof(dialinginfo));
1141 SCPY(dialinginfo.id, cfp);
1142 dialinginfo.itype = INFO_ITYPE_ISDN;
1143 dialinginfo.ntype = e_dialinginfo.ntype;
1144 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1146 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1148 goto check_anycall_intern;
1150 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1151 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1152 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1153 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1154 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1155 /* if clip is hidden */
1156 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1157 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1158 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1159 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1160 message->param.setup.callerinfo.present = e_ext.callerid_present;
1161 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1163 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1164 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1165 //terminal if (e_dialinginfo.id)
1166 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1167 /* handle restricted caller ids */
1168 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1169 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1170 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1171 /* display callerid if desired for extension */
1172 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
1173 message_put(message);
1174 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1178 check_anycall_intern:
1179 /* now we have all ports created */
1181 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1183 if (!ea_endpoint->ep_join_id)
1185 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1186 return; /* must exit here */
1190 /* *********************** external call */
1192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1193 /* call to extenal interfaces */
1194 if (e_dialinginfo.keypad[0])
1195 p = e_dialinginfo.keypad;
1197 p = e_dialinginfo.id;
1200 while(*p!=',' && *p!='\0')
1201 SCCAT(number, *p++);
1205 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1206 /* hunt for mISDNport and create Port */
1207 /* hunt for mISDNport and create Port */
1208 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1210 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1211 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1213 goto check_anycall_extern;
1215 /* creating EXTERNAL port*/
1216 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1219 port = ss5_hunt_line(mISDNport);
1223 if (mISDNport->gsm_bs)
1224 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1228 if (mISDNport->gsm_ms)
1229 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1233 if (mISDNport->ifport->interface->sip)
1234 port = new Psip(PORT_TYPE_SIP_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, mISDNport->ifport->interface);
1237 if (mISDNport->ifport->remote) {
1238 admin = admin_first;
1240 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1242 admin = admin->next;
1245 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1246 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1250 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1252 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1254 FATAL("No memory for Port instance\n");
1255 earlyb = mISDNport->earlyb;
1256 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1257 memset(&dialinginfo, 0, sizeof(dialinginfo));
1258 if (e_dialinginfo.keypad[0])
1259 SCPY(dialinginfo.keypad, number);
1261 SCPY(dialinginfo.id, number);
1262 dialinginfo.itype = INFO_ITYPE_ISDN;
1263 dialinginfo.ntype = e_dialinginfo.ntype;
1264 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1265 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1267 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1269 goto check_anycall_extern;
1271 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1272 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1273 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1274 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1275 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1276 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1277 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1278 //terminal if (e_dialinginfo.id)
1279 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1280 /* handle restricted caller ids */
1281 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1282 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1283 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1284 /* display callerid if desired for extension */
1285 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
1286 message_put(message);
1287 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1291 check_anycall_extern:
1292 /* now we have all ports created */
1294 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1296 if (!ea_endpoint->ep_join_id)
1298 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1299 return; /* must exit here */
1306 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1308 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1310 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1313 unsched_timer(&ea->e_redial_timeout);
1314 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1315 ea->e_multipoint_cause = 0;
1316 ea->e_multipoint_location = 0;
1317 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1318 ea->e_join_pattern = 0;
1319 ea->process_dialing(1);
1320 /* we must exit, because our endpoint might be gone */
1325 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1327 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1329 if (!ea->e_action) {
1330 unsched_timer(&ea->e_redial_timeout);
1331 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1332 ea->process_dialing(0);
1333 /* we must exit, because our endpoint might be gone */
1339 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1341 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1343 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1345 ea->new_state(EPOINT_STATE_OUT_SETUP);
1346 /* call special setup routine */
1352 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1354 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1356 /* leave power dialing on */
1357 ea->e_powerdial_on = 1;
1358 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1361 ea->e_ruleset = ruleset_main;
1363 ea->e_rule = ea->e_ruleset->rule_first;
1364 ea->e_action = NULL;
1365 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1366 ea->process_dialing(0);
1371 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1373 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1374 struct port_list *portlist;
1375 struct lcr_msg *message;
1377 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1379 /* release all ports */
1380 while((portlist = ea->ea_endpoint->ep_portlist)) {
1381 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1382 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1383 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1384 message_put(message);
1385 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1386 ea->ea_endpoint->free_portlist(portlist);
1389 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1390 message->param.audiopath = 0;
1391 message_put(message);
1392 /* indicate no patterns */
1393 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1394 message_put(message);
1395 /* set setup state, since we have no response from the new join */
1396 ea->new_state(EPOINT_STATE_OUT_SETUP);
1401 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1403 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1405 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr);
1411 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1413 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1415 if (ea->e_state == EPOINT_STATE_IDLE) {
1416 /* epoint is idle, check callback */
1417 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1418 ea->new_state(EPOINT_STATE_OUT_SETUP);
1425 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1427 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1429 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1430 struct port_list *portlist;
1432 ea->e_ruleset = ruleset_main;
1434 ea->e_rule = ea->e_ruleset->rule_first;
1435 ea->e_action = NULL;
1436 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1437 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1439 ea->e_connectedmode = 0;
1441 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1442 portlist = ea->ea_endpoint->ep_portlist;
1444 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1445 ea->set_tone(portlist, "cause_10");
1452 /* doing a hookflash */
1453 void EndpointAppPBX::hookflash(void)
1458 /* be sure that we are active */
1460 e_tx_state = NOTIFY_STATE_ACTIVE;
1462 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1464 if (ea_endpoint->ep_use > 1) {
1465 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1468 /* dialtone after pressing the hash key */
1469 process_hangup(e_join_cause, e_join_location);
1470 e_multipoint_cause = 0;
1471 e_multipoint_location = 0;
1472 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1474 port->set_echotest(0);
1476 if (ea_endpoint->ep_join_id) {
1477 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1479 e_ruleset = ruleset_main;
1481 e_rule = e_ruleset->rule_first;
1483 new_state(EPOINT_STATE_IN_OVERLAP);
1484 e_connectedmode = 1;
1485 SCPY(e_dialinginfo.id, e_ext.prefix);
1486 e_extdialing = e_dialinginfo.id;
1488 if (e_dialinginfo.id[0]) {
1489 set_tone(ea_endpoint->ep_portlist, "dialing");
1492 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1500 /* messages from port
1502 /* port MESSAGE_SETUP */
1503 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1505 struct lcr_msg *message;
1507 int writeext; /* flags need to write extension after modification */
1509 struct interface *interface;
1511 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1513 portlist->port_type = param->setup.port_type;
1514 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1515 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1516 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1517 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1519 /* convert (inter-)national number type */
1520 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1521 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1523 // e_dtmf = param->setup.dtmf;
1524 /* screen incoming caller id */
1525 interface = interface_first;
1527 if (!strcmp(e_callerinfo.interface, interface->name)) {
1530 interface = interface->next;
1533 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1534 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1537 /* process extension */
1538 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1539 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1540 /* port makes call from extension */
1541 SCPY(e_callerinfo.extension, e_callerinfo.id);
1542 SCPY(e_ext.number, e_callerinfo.extension);
1543 SCPY(e_extension_interface, e_callerinfo.interface);
1545 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1548 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1549 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1551 /* get extension's info about caller */
1552 if (!read_extension(&e_ext, e_ext.number)) {
1553 /* extension doesn't exist */
1554 trace_header("EXTENSION (not created)", DIRECTION_IN);
1555 add_trace("extension", NULL, "%s", e_ext.number);
1557 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1558 new_state(EPOINT_STATE_OUT_DISCONNECT);
1559 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1560 e_ext.number[0] = '\0'; /* no terminal */
1565 /* put prefix (next) in front of e_dialinginfo.id */
1566 if (e_ext.next[0]) {
1567 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1568 SCPY(e_dialinginfo.id, buffer);
1569 e_ext.next[0] = '\0';
1571 } else if (e_ext.prefix[0]) {
1572 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1573 SCPY(e_dialinginfo.id, buffer);
1576 /* screen caller id by extension's config */
1577 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1579 SCPY(e_callerinfo.name, e_ext.name);
1580 /* use caller id (or if exist: id_next_call) for this call */
1581 if (e_ext.id_next_call_present >= 0) {
1582 SCPY(e_callerinfo.id, e_ext.id_next_call);
1583 /* if we restrict the pesentation */
1584 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1585 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1586 else e_callerinfo.present = e_ext.id_next_call_present;
1587 e_callerinfo.ntype = e_ext.id_next_call_type;
1588 e_ext.id_next_call_present = -1;
1591 SCPY(e_callerinfo.id, e_ext.callerid);
1592 /* if we restrict the pesentation */
1593 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1594 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1595 else e_callerinfo.present = e_ext.callerid_present;
1596 e_callerinfo.ntype = e_ext.callerid_type;
1598 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1600 /* extension is written */
1602 write_extension(&e_ext, e_ext.number);
1604 /* set volume of rx and tx */
1605 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1606 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1607 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1608 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1609 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1610 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1611 message_put(message);
1614 /* start recording if enabled */
1615 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1616 /* check if we are a terminal */
1617 if (e_ext.number[0] == '\0')
1618 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1620 port = find_port_id(portlist->port_id);
1622 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1626 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1627 /* no terminal identification */
1628 e_ext.number[0] = '\0';
1629 e_extension_interface[0] = '\0';
1630 memset(&e_ext, 0, sizeof(e_ext));
1631 e_ext.rights = 4; /* right to dial internat */
1635 e_ruleset = ruleset_main;
1637 e_rule = e_ruleset->rule_first;
1639 e_extdialing = e_dialinginfo.id;
1640 new_state(EPOINT_STATE_IN_SETUP);
1641 if (e_dialinginfo.id[0]) {
1642 set_tone(portlist, "dialing");
1644 if (e_ext.number[0])
1645 set_tone(portlist, "dialpbx");
1647 set_tone(portlist, "dialtone");
1650 if (e_state == EPOINT_STATE_IN_SETUP) {
1651 /* request MORE info, if not already at higher state */
1652 new_state(EPOINT_STATE_IN_OVERLAP);
1653 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1654 message_put(message);
1655 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1659 /* port MESSAGE_INFORMATION */
1660 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1662 struct lcr_msg *message;
1664 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1666 /* ignore information message without digit information */
1667 if (!param->information.id[0])
1672 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1674 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1679 /* if vbox_play is done, the information are just used as they come */
1681 if (e_action->index == ACTION_VBOX_PLAY) {
1682 /* concat dialing string */
1683 SCAT(e_dialinginfo.id, param->information.id);
1688 /* keypad when disconnect but in connected mode */
1689 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1690 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1691 /* processing keypad function */
1692 if (param->information.id[0] == '0') {
1698 /* keypad when connected */
1699 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1700 if (e_enablekeypad) {
1701 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1702 memcpy(&message->param, param, sizeof(union parameter));
1703 message_put(message);
1707 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1708 /* processing keypad function */
1709 if (param->information.id[0] == '0') {
1712 if (param->information.id[0])
1713 keypad_function(param->information.id[0]);
1715 if (e_ext.number[0])
1716 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1718 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1723 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1724 if (e_ext.number[0])
1725 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1727 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1731 if (!param->information.id[0])
1733 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1734 set_tone(portlist, "dialing");
1737 if (e_action->index==ACTION_OUTDIAL
1738 || e_action->index==ACTION_EXTERNAL
1739 || e_action->index==ACTION_REMOTE) {
1741 set_tone(portlist, "dialing");
1742 else if (!e_extdialing[0])
1743 set_tone(portlist, "dialing");
1745 /* concat dialing string */
1746 SCAT(e_dialinginfo.id, param->information.id);
1750 /* port MESSAGE_DTMF */
1751 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1754 struct lcr_msg *message;
1758 /* only if dtmf detection is enabled */
1760 trace_header("DTMF (disabled)", DIRECTION_IN);
1764 trace_header("DTMF", DIRECTION_IN);
1765 add_trace("digit", NULL, "%c", param->dtmf);
1769 NOTE: vbox is now handled due to overlap state
1770 /* if vbox_play is done, the dtmf digits are just used as they come */
1772 if (e_action->index == ACTION_VBOX_PLAY) {
1773 /* concat dialing string */
1774 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1775 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1776 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1779 /* continue to process *X# sequences */
1783 /* check for *X# sequence */
1784 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1785 if (e_enablekeypad) {
1786 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1787 memcpy(&message->param, param, sizeof(union parameter));
1788 message_put(message);
1791 if (e_dtmf_time+3 < now) {
1792 /* the last digit was too far in the past to be a sequence */
1793 if (param->dtmf == '*')
1794 /* only start is allowed in the sequence */
1799 /* we have a sequence of digits, see what we got */
1800 if (param->dtmf == '*')
1802 else if (param->dtmf>='0' && param->dtmf<='9') {
1803 /* we need to have a star before we receive the digit of the sequence */
1804 if (e_dtmf_last == '*')
1805 e_dtmf_last = param->dtmf;
1806 } else if (param->dtmf == '#') {
1808 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1809 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1810 if (e_dtmf_last == '0') {
1814 /* processing keypad function */
1816 keypad_function(e_dtmf_last);
1822 /* set last time of dtmf */
1827 /* check for ## hookflash during dialing */
1829 if (e_action->index==ACTION_PASSWORD
1830 || e_action->index==ACTION_PASSWORD_WRITE)
1832 if (param->dtmf=='#') { /* current digit is '#' */
1833 if (e_state==EPOINT_STATE_IN_DISCONNECT
1834 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1848 /* dialing using dtmf digit */
1849 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1850 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1851 set_tone(portlist, "dialing");
1853 /* concat dialing string */
1854 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1855 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1856 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1862 /* port MESSAGE_CRYPT */
1863 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1865 /* send crypt response to cryptman */
1866 if (param->crypt.type == CR_MESSAGE_IND)
1867 cryptman_msg2man(param->crypt.data, param->crypt.len);
1869 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1872 /* port MESSAGE_OVERLAP */
1873 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1875 struct lcr_msg *message;
1877 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1879 /* signal to call tool */
1880 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1882 if (e_dialing_queue[0] && portlist) {
1883 /* send what we have not dialed yet, because we had no setup complete */
1884 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1885 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1886 SCPY(message->param.information.id, e_dialing_queue);
1887 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1888 message_put(message);
1889 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1890 e_dialing_queue[0] = '\0';
1892 /* check if pattern is available */
1893 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1894 /* indicate patterns */
1895 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1896 message_put(message);
1898 /* connect audio, if not already */
1899 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1900 message->param.audiopath = 1;
1901 message_put(message);
1903 /* indicate no patterns */
1904 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1905 message_put(message);
1907 /* disconnect audio, if not already */
1908 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1909 message->param.audiopath = 0;
1910 message_put(message);
1912 new_state(EPOINT_STATE_OUT_OVERLAP);
1913 /* if we are in a join */
1914 if (ea_endpoint->ep_join_id) {
1915 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1916 memcpy(&message->param, param, sizeof(union parameter));
1917 message_put(message);
1921 /* port MESSAGE_PROCEEDING */
1922 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1924 struct lcr_msg *message;
1926 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1928 /* signal to call tool */
1929 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1931 e_state = EPOINT_STATE_OUT_PROCEEDING;
1932 /* check if pattern is availatle */
1933 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1934 /* indicate patterns */
1935 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1936 message_put(message);
1938 /* connect audio, if not already */
1939 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1940 message->param.audiopath = 1;
1941 message_put(message);
1943 /* indicate no patterns */
1944 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1945 message_put(message);
1947 /* disconnect audio, if not already */
1948 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1949 message->param.audiopath = 0;
1950 message_put(message);
1952 /* if we are in a call */
1953 if (ea_endpoint->ep_join_id) {
1954 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1955 memcpy(&message->param, param, sizeof(union parameter));
1956 message_put(message);
1960 /* port MESSAGE_ALERTING */
1961 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1963 struct lcr_msg *message;
1965 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1967 /* signal to call tool */
1968 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1971 // set_tone(portlist, "hold");
1973 new_state(EPOINT_STATE_OUT_ALERTING);
1974 /* check if pattern is available */
1975 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1976 /* indicate patterns */
1977 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1978 message_put(message);
1980 /* connect audio, if not already */
1981 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1982 message->param.audiopath = 1;
1983 message_put(message);
1985 /* indicate no patterns */
1986 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1987 message_put(message);
1989 /* disconnect audio, if not already */
1990 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1991 message->param.audiopath = 0;
1992 message_put(message);
1994 /* if we are in a call */
1995 if (ea_endpoint->ep_join_id) {
1996 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1997 memcpy(&message->param, param, sizeof(union parameter));
1998 message_put(message);
2002 /* port MESSAGE_CONNECT */
2003 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
2005 struct lcr_msg *message;
2007 unsigned int port_id = portlist->port_id;
2008 struct port_list *tportlist;
2010 struct interface *interface;
2013 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2015 /* signal to call tool */
2016 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
2018 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
2019 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2020 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
2021 tportlist = ea_endpoint->ep_portlist;
2022 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2023 tportlist = tportlist->next;
2024 if (tportlist->port_id == port_id)
2025 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2026 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2027 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
2028 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2029 message_put(message);
2030 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
2031 ea_endpoint->free_portlist(tportlist);
2033 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2038 /* screen incoming connected id */
2039 interface = interface_first;
2041 if (!strcmp(e_connectinfo.interface, interface->name)) {
2044 interface = interface->next;
2047 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
2049 /* screen connected name */
2051 SCPY(e_connectinfo.name, e_ext.name);
2053 /* add internal id to colp */
2054 SCPY(e_connectinfo.extension, e_ext.number);
2056 /* we store the connected port number */
2057 SCPY(e_extension_interface, e_connectinfo.interface);
2059 /* for internal and am calls, we get the extension's id */
2060 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
2061 SCPY(e_connectinfo.id, e_ext.callerid);
2062 SCPY(e_connectinfo.extension, e_ext.number);
2063 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2064 e_connectinfo.ntype = e_ext.callerid_type;
2065 e_connectinfo.present = e_ext.callerid_present;
2067 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2068 e_connectinfo.itype = INFO_ITYPE_VBOX;
2069 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2072 new_state(EPOINT_STATE_CONNECT);
2074 /* set volume of rx and tx */
2075 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2076 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2077 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2078 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2079 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2080 message_put(message);
2083 unsched_timer(&e_cfnr_timeout);
2084 unsched_timer(&e_cfnr_call_timeout);
2085 if (e_ext.number[0])
2086 e_dtmf = 1; /* allow dtmf */
2089 /* other calls with no caller id (or not available for the extension) and force colp */
2090 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2091 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2092 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
2093 /* external extension answered */
2094 port = find_port_id(portlist->port_id);
2096 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2097 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2102 /* send connect to join */
2103 if (ea_endpoint->ep_join_id) {
2104 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2105 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2106 message_put(message);
2108 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2109 message->param.audiopath = 1;
2110 message_put(message);
2111 } else if (!e_adminid) {
2113 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2114 SCPY(e_ext.number, e_cbcaller);
2115 new_state(EPOINT_STATE_IN_OVERLAP);
2116 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2118 /* get extension's info about terminal */
2119 if (!read_extension(&e_ext, e_ext.number)) {
2120 /* extension doesn't exist */
2121 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2122 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2123 new_state(EPOINT_STATE_OUT_DISCONNECT);
2124 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2128 /* put prefix in front of e_cbdialing */
2129 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2130 SCPY(e_dialinginfo.id, buffer);
2131 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2132 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2134 /* use caller id (or if exist: id_next_call) for this call */
2135 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2136 SCPY(e_callerinfo.extension, e_ext.number);
2137 if (e_ext.id_next_call_present >= 0) {
2138 SCPY(e_callerinfo.id, e_ext.id_next_call);
2139 e_callerinfo.present = e_ext.id_next_call_present;
2140 e_callerinfo.ntype = e_ext.id_next_call_type;
2141 e_ext.id_next_call_present = -1;
2142 /* extension is written */
2143 write_extension(&e_ext, e_ext.number);
2145 SCPY(e_callerinfo.id, e_ext.callerid);
2146 e_callerinfo.present = e_ext.callerid_present;
2147 e_callerinfo.ntype = e_ext.callerid_type;
2149 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2151 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2154 /* check if caller id is NOT authenticated */
2155 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2156 /* make call state to enter password */
2157 new_state(EPOINT_STATE_IN_OVERLAP);
2158 e_action = &action_password_write;
2159 unsched_timer(&e_match_timeout);
2160 e_match_to_action = NULL;
2161 e_dialinginfo.id[0] = '\0';
2162 e_extdialing = strchr(e_dialinginfo.id, '\0');
2163 schedule_timer(&e_password_timeout, 20, 0);
2166 /* incoming call (callback) */
2167 e_ruleset = ruleset_main;
2169 e_rule = e_ruleset->rule_first;
2171 e_extdialing = e_dialinginfo.id;
2172 if (e_dialinginfo.id[0]) {
2173 set_tone(portlist, "dialing");
2176 set_tone(portlist, "dialpbx");
2179 } else { /* testcall */
2180 set_tone(portlist, "hold");
2183 /* start recording if enabled, not when answering machine answers */
2184 if (param->connectinfo.itype!=INFO_ITYPE_VBOX && e_ext.number[0] && e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
2185 /* check if we are a terminal */
2186 if (e_ext.number[0] == '\0')
2187 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2189 port = find_port_id(portlist->port_id);
2191 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2196 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2197 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2199 struct lcr_msg *message;
2201 unsigned int port_id = portlist->port_id;
2205 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2207 /* signal to call tool */
2208 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2210 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2211 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2212 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2217 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current multipoint cause %d location %d, received cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2218 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2219 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2221 /* check if we have more than one portlist relation and we just ignore the disconnect */
2222 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2223 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2224 portlist = ea_endpoint->ep_portlist;
2226 if (portlist->port_id == port_id)
2228 portlist = portlist->next;
2231 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2232 if (message_type != MESSAGE_RELEASE) {
2233 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2234 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2235 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2236 message_put(message);
2237 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2239 ea_endpoint->free_portlist(portlist);
2240 return; /* one relation removed */
2242 if (e_state == EPOINT_STATE_CONNECT) {
2243 /* use cause from port after connect */
2244 cause = param->disconnectinfo.cause;
2245 location = param->disconnectinfo.location;
2247 /* use multipoint cause if no connect yet */
2248 if (e_multipoint_cause) {
2249 cause = e_multipoint_cause;
2250 location = e_multipoint_location;
2252 cause = CAUSE_NOUSER;
2253 location = LOCATION_PRIVATE_LOCAL;
2257 unsched_timer(&e_cfnr_timeout);
2258 unsched_timer(&e_cfnr_call_timeout);
2260 /* process hangup */
2261 process_hangup(e_join_cause, e_join_location);
2262 e_multipoint_cause = 0;
2263 e_multipoint_location = 0;
2265 if (message_type == MESSAGE_DISCONNECT) {
2266 /* tone to disconnected end */
2267 SPRINT(buffer, "cause_%02x", cause);
2268 if (ea_endpoint->ep_portlist)
2269 set_tone(ea_endpoint->ep_portlist, buffer);
2271 new_state(EPOINT_STATE_IN_DISCONNECT);
2274 if (ea_endpoint->ep_join_id) {
2275 int haspatterns = 0;
2276 /* check if pattern is available */
2277 if (ea_endpoint->ep_portlist)
2278 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2279 if (joinpbx_countrelations(ea_endpoint->ep_join_id)==2 // we must count relations, in order not to disturb the conference ; NOTE: asterisk always counts two, since it is a point to point call
2280 && message_type != MESSAGE_RELEASE) // if we release, we are done
2283 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2284 /* indicate patterns */
2285 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2286 message_put(message);
2287 /* connect audio, if not already */
2288 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2289 message->param.audiopath = 1;
2290 message_put(message);
2291 /* send disconnect */
2292 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2293 memcpy(&message->param, param, sizeof(union parameter));
2294 message_put(message);
2295 /* disable encryption if disconnected */
2296 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2298 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2301 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2304 if (message_type == MESSAGE_RELEASE)
2305 ea_endpoint->free_portlist(portlist);
2306 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2307 return; /* must exit here */
2310 /* port MESSAGE_TIMEOUT */
2311 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2315 trace_header("TIMEOUT", DIRECTION_IN);
2316 message_type = MESSAGE_DISCONNECT;
2317 switch (param->state) {
2318 case PORT_STATE_OUT_SETUP:
2319 case PORT_STATE_OUT_OVERLAP:
2320 add_trace("state", NULL, "outgoing setup/dialing");
2322 /* no user responding */
2323 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2324 return; /* must exit here */
2326 case PORT_STATE_IN_SETUP:
2327 case PORT_STATE_IN_OVERLAP:
2328 add_trace("state", NULL, "incoming setup/dialing");
2329 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2330 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2333 case PORT_STATE_OUT_PROCEEDING:
2334 add_trace("state", NULL, "outgoing proceeding");
2336 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2337 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2338 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2339 return; /* must exit here */
2341 case PORT_STATE_IN_PROCEEDING:
2342 add_trace("state", NULL, "incoming proceeding");
2343 param->disconnectinfo.cause = CAUSE_NOUSER;
2344 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2347 case PORT_STATE_OUT_ALERTING:
2348 add_trace("state", NULL, "outgoing alerting");
2350 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2351 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2352 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2353 return; /* must exit here */
2355 case PORT_STATE_CONNECT:
2356 add_trace("state", NULL, "connect");
2358 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2359 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2360 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2361 return; /* must exit here */
2363 case PORT_STATE_IN_ALERTING:
2364 add_trace("state", NULL, "incoming alerting");
2365 param->disconnectinfo.cause = CAUSE_NOANSWER;
2366 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2369 case PORT_STATE_IN_DISCONNECT:
2370 case PORT_STATE_OUT_DISCONNECT:
2371 add_trace("state", NULL, "disconnect");
2373 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2374 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2375 return; /* must exit here */
2378 param->disconnectinfo.cause = 31; /* normal unspecified */
2379 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2382 /* release call, disconnect isdn */
2384 new_state(EPOINT_STATE_OUT_DISCONNECT);
2385 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2386 SCPY(e_tone, cause);
2388 set_tone(portlist, cause);
2389 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2390 portlist = portlist->next;
2392 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2395 /* port MESSAGE_NOTIFY */
2396 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2398 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2400 struct lcr_msg *message;
2401 const char *logtext = "";
2404 /* signal to call tool */
2405 admin_call_response(e_adminid, ADMIN_CALL_NOTIFY, numberrize_callerinfo(param->notifyinfo.id,param->notifyinfo.ntype, options.national, options.international), 0, 0, param->notifyinfo.notify);
2406 if (param->notifyinfo.notify) {
2407 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2410 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2411 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2412 case INFO_NOTIFY_REMOTE_HOLD:
2413 case INFO_NOTIFY_USER_SUSPENDED:
2414 /* tell call about it */
2415 if (ea_endpoint->ep_join_id) {
2416 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2417 message->param.audiopath = 0;
2418 message_put(message);
2422 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2423 case INFO_NOTIFY_USER_RESUMED:
2424 /* set volume of rx and tx */
2425 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2426 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2428 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2429 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2430 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2431 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2432 message_put(message);
2434 /* set current tone */
2436 set_tone(portlist, e_tone);
2437 /* tell call about it */
2438 if (ea_endpoint->ep_join_id) {
2439 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2440 message->param.audiopath = 1;
2441 message_put(message);
2446 /* get name of notify */
2447 switch(param->notifyinfo.notify) {
2452 logtext = "USER_SUSPENDED";
2455 logtext = "BEARER_SERVICE_CHANGED";
2458 logtext = "USER_RESUMED";
2461 logtext = "CONFERENCE_ESTABLISHED";
2464 logtext = "CONFERENCE_DISCONNECTED";
2467 logtext = "OTHER_PARTY_ADDED";
2470 logtext = "ISOLATED";
2473 logtext = "REATTACHED";
2476 logtext = "OTHER_PARTY_ISOLATED";
2479 logtext = "OTHER_PARTY_REATTACHED";
2482 logtext = "OTHER_PARTY_SPLIT";
2485 logtext = "OTHER_PARTY_DISCONNECTED";
2488 logtext = "CONFERENCE_FLOATING";
2491 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2494 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2497 logtext = "CALL_IS_A_WAITING_CALL";
2500 logtext = "DIVERSION_ACTIVATED";
2503 logtext = "RESERVED_CT_1";
2506 logtext = "RESERVED_CT_2";
2509 logtext = "REVERSE_CHARGING";
2512 logtext = "REMOTE_HOLD";
2515 logtext = "REMOTE_RETRIEVAL";
2518 logtext = "CALL_IS_DIVERTING";
2521 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2526 /* notify call if available */
2527 if (ea_endpoint->ep_join_id) {
2528 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2529 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2530 message_put(message);
2535 /* port MESSAGE_PROGRESS */
2536 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2538 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2540 struct lcr_msg *message;
2542 /* signal to call tool */
2543 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2545 /* send progress to call if available */
2546 if (ea_endpoint->ep_join_id) {
2547 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2548 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2549 message_put(message);
2554 /* port MESSAGE_FACILITY */
2555 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2557 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2559 struct lcr_msg *message;
2561 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2562 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2563 message_put(message);
2566 /* port MESSAGE_SUSPEND */
2567 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2568 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2570 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2572 /* epoint is now parked */
2573 ea_endpoint->ep_park = 1;
2574 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2575 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2577 /* remove port relation */
2578 ea_endpoint->free_portlist(portlist);
2581 /* port MESSAGE_RESUME */
2582 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2583 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2585 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2587 /* epoint is now resumed */
2588 ea_endpoint->ep_park = 0;
2592 /* port MESSAGE_ENABLEKEYPAD */
2593 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2595 struct lcr_msg *message;
2597 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2599 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2600 memcpy(&message->param, param, sizeof(union parameter));
2601 message_put(message);
2605 /* port sends message to the endpoint
2607 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2609 struct port_list *portlist;
2611 portlist = ea_endpoint->ep_portlist;
2613 if (port_id == portlist->port_id)
2615 portlist = portlist->next;
2618 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) warning: port is not related to this endpoint. This may happen, if port has been released after the message was created.\n", ea_endpoint->ep_serial);
2622 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2623 switch(message_type) {
2624 case MESSAGE_TONE_EOF: /* tone is end of file */
2625 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2627 if (e_action->index == ACTION_VBOX_PLAY) {
2630 if (e_action->index == ACTION_EFI) {
2636 case MESSAGE_TONE_COUNTER: /* counter info received */
2637 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);
2639 if (e_action->index == ACTION_VBOX_PLAY) {
2640 e_vbox_counter = param->counter.current;
2641 if (param->counter.max >= 0)
2642 e_vbox_counter_max = param->counter.max;
2646 /* PORT sends SETUP message */
2648 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);
2649 if (e_state!=EPOINT_STATE_IDLE) {
2650 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2653 port_setup(portlist, message_type, param);
2656 /* PORT sends INFORMATION message */
2657 case MESSAGE_INFORMATION: /* additional digits received */
2658 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);
2659 port_information(portlist, message_type, param);
2662 /* PORT sends FACILITY message */
2663 case MESSAGE_FACILITY:
2664 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2665 port_facility(portlist, message_type, param);
2668 /* PORT sends DTMF message */
2669 case MESSAGE_DTMF: /* dtmf digits received */
2670 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);
2671 port_dtmf(portlist, message_type, param);
2674 /* PORT sends CRYPT message */
2675 case MESSAGE_CRYPT: /* crypt response received */
2676 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2677 port_crypt(portlist, message_type, param);
2680 /* PORT sends MORE message */
2681 case MESSAGE_OVERLAP:
2682 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);
2683 if (e_state != EPOINT_STATE_OUT_SETUP) {
2684 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);
2687 port_overlap(portlist, message_type, param);
2690 /* PORT sends PROCEEDING message */
2691 case MESSAGE_PROCEEDING: /* port is proceeding */
2692 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);
2693 if (e_state!=EPOINT_STATE_OUT_SETUP
2694 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2695 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);
2698 port_proceeding(portlist, message_type, param);
2701 /* PORT sends ALERTING message */
2702 case MESSAGE_ALERTING:
2703 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);
2704 if (e_state!=EPOINT_STATE_OUT_SETUP
2705 && e_state!=EPOINT_STATE_OUT_OVERLAP
2706 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2707 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);
2710 port_alerting(portlist, message_type, param);
2713 /* PORT sends CONNECT message */
2714 case MESSAGE_CONNECT:
2715 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);
2716 if (e_state!=EPOINT_STATE_OUT_SETUP
2717 && e_state!=EPOINT_STATE_OUT_OVERLAP
2718 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2719 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2720 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2723 port_connect(portlist, message_type, param);
2726 /* PORT sends DISCONNECT message */
2727 case MESSAGE_DISCONNECT: /* port is disconnected */
2728 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);
2729 port_disconnect_release(portlist, message_type, param);
2732 /* PORT sends a RELEASE message */
2733 case MESSAGE_RELEASE: /* port releases */
2734 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);
2735 /* portlist is release at port_disconnect_release, thanx Paul */
2736 port_disconnect_release(portlist, message_type, param);
2739 /* PORT sends a TIMEOUT message */
2740 case MESSAGE_TIMEOUT:
2741 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);
2742 port_timeout(portlist, message_type, param);
2743 break; /* release */
2745 /* PORT sends a NOTIFY message */
2746 case MESSAGE_NOTIFY:
2747 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);
2748 port_notify(portlist, message_type, param);
2751 /* PORT sends a PROGRESS message */
2752 case MESSAGE_PROGRESS:
2753 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);
2754 port_progress(portlist, message_type, param);
2757 /* PORT sends a SUSPEND message */
2758 case MESSAGE_SUSPEND:
2759 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);
2760 port_suspend(portlist, message_type, param);
2761 break; /* suspend */
2763 /* PORT sends a RESUME message */
2764 case MESSAGE_RESUME:
2765 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);
2766 port_resume(portlist, message_type, param);
2770 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2771 /* port assigns bchannel */
2772 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2773 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);
2774 /* only one port is expected to be connected to bchannel */
2775 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2776 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2780 /* PORT requests DTMF */
2781 case MESSAGE_ENABLEKEYPAD:
2782 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);
2783 port_enablekeypad(portlist, message_type, param);
2788 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);
2791 /* Note: this endpoint may be destroyed, so we MUST return */
2795 /* messages from join
2797 /* join MESSAGE_CRYPT */
2798 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2800 switch(param->crypt.type) {
2801 /* message from remote port to "crypt manager" */
2802 case CU_ACTK_REQ: /* activate key-exchange */
2803 case CU_ACTS_REQ: /* activate shared key */
2804 case CU_DACT_REQ: /* deactivate */
2805 case CU_INFO_REQ: /* request last info message */
2806 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2809 /* message from "crypt manager" to user */
2810 case CU_ACTK_CONF: /* key-echange done */
2811 case CU_ACTS_CONF: /* shared key done */
2812 case CU_DACT_CONF: /* deactivated */
2813 case CU_DACT_IND: /* deactivated */
2814 case CU_ERROR_IND: /* receive error message */
2815 case CU_INFO_IND: /* receive info message */
2816 case CU_INFO_CONF: /* receive info message */
2817 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2821 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);
2825 /* join MESSAGE_INFORMATION */
2826 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2828 struct lcr_msg *message;
2833 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2834 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2835 message_put(message);
2836 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2837 portlist = portlist->next;
2841 /* join MESSAGE_FACILITY */
2842 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2844 struct lcr_msg *message;
2846 if (!e_ext.facility && e_ext.number[0]) {
2851 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2852 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2853 message_put(message);
2854 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2855 portlist = portlist->next;
2859 /* join MESSAGE_MORE */
2860 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2862 struct lcr_msg *message;
2864 new_state(EPOINT_STATE_IN_OVERLAP);
2867 if (e_join_pattern && e_ext.own_setup) {
2868 /* disconnect audio */
2869 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2870 message->param.audiopath = 0;
2871 message_put(message);
2873 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2874 if (e_dialinginfo.id[0])
2875 set_tone(portlist, "dialing");
2877 set_tone(portlist, "dialtone");
2880 if (e_dialinginfo.id[0]) {
2881 set_tone(portlist, "dialing");
2883 if (e_ext.number[0])
2884 set_tone(portlist, "dialpbx");
2886 set_tone(portlist, "dialtone");
2890 /* join MESSAGE_PROCEEDING */
2891 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2893 struct lcr_msg *message;
2895 new_state(EPOINT_STATE_IN_PROCEEDING);
2897 /* own proceeding tone */
2898 if (e_join_pattern) {
2899 /* connect / disconnect audio */
2900 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2901 if (e_ext.own_proceeding)
2902 message->param.audiopath = 0;
2904 message->param.audiopath = 1;
2905 message_put(message);
2907 // UCPY(e_join_tone, "proceeding");
2909 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2910 message_put(message);
2911 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2913 set_tone(portlist, "proceeding");
2916 /* join MESSAGE_ALERTING */
2917 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2919 struct lcr_msg *message;
2921 new_state(EPOINT_STATE_IN_ALERTING);
2923 /* own alerting tone */
2924 if (e_join_pattern) {
2925 /* connect / disconnect audio */
2926 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2927 if (e_ext.own_alerting)
2928 message->param.audiopath = 0;
2930 message->param.audiopath = 1;
2931 message_put(message);
2934 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2935 message_put(message);
2936 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2938 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2939 set_tone(portlist, "ringing");
2942 if (e_ext.number[0])
2943 set_tone(portlist, "ringpbx");
2945 set_tone(portlist, "ringing");
2947 if (e_ext.number[0])
2948 e_dtmf = 1; /* allow dtmf */
2951 /* join MESSAGE_CONNECT */
2952 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2954 struct lcr_msg *message;
2957 new_state(EPOINT_STATE_CONNECT);
2958 // UCPY(e_join_tone, "");
2960 if (e_ext.number[0])
2961 e_dtmf = 1; /* allow dtmf */
2964 unsched_timer(&e_powerdial_timeout);
2965 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2967 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2968 memcpy(&message->param, param, sizeof(union parameter));
2970 /* screen clip if prefix is required */
2971 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2972 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2973 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2974 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2977 /* use internal caller id */
2978 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2979 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2980 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2983 /* handle restricted caller ids */
2984 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);
2985 /* display callerid if desired for extension */
2986 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));
2988 /* use conp, if enabld */
2989 // if (!e_ext.centrex)
2990 // message->param.connectinfo.name[0] = '\0';
2993 message_put(message);
2994 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2996 set_tone(portlist, NULL);
2998 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2999 message->param.audiopath = 1;
3000 message_put(message);
3005 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3006 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3009 struct lcr_msg *message;
3010 struct port_list *portlist = NULL;
3014 /* be sure that we are active */
3016 e_tx_state = NOTIFY_STATE_ACTIVE;
3018 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
3019 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
3020 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
3022 /* set time for power dialing */
3023 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
3026 /* set redial tone */
3027 if (ea_endpoint->ep_portlist) {
3030 set_tone(ea_endpoint->ep_portlist, "redial");
3031 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);
3032 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3033 if (e_state==EPOINT_STATE_IN_OVERLAP) {
3034 new_state(EPOINT_STATE_IN_PROCEEDING);
3035 if (ea_endpoint->ep_portlist) {
3036 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3037 message_put(message);
3038 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3040 /* caused the error, that the first knock sound was not there */
3041 /* set_tone(portlist, "proceeding"); */
3043 /* send display of powerdialing */
3044 if (e_ext.display_dialing) {
3045 portlist = ea_endpoint->ep_portlist;
3047 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3049 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3051 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3052 message_put(message);
3053 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3054 portlist = portlist->next;
3064 if ((e_state!=EPOINT_STATE_CONNECT
3065 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3066 && e_state!=EPOINT_STATE_IN_OVERLAP
3067 && e_state!=EPOINT_STATE_IN_PROCEEDING
3068 && e_state!=EPOINT_STATE_IN_ALERTING)
3069 || !ea_endpoint->ep_portlist) { /* or no port */
3070 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3071 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3072 return; /* must exit here */
3075 if (!e_join_cause) {
3076 e_join_cause = param->disconnectinfo.cause;
3077 e_join_location = param->disconnectinfo.location;
3080 /* on release we need the audio again! */
3081 if (message_type == MESSAGE_RELEASE) {
3083 ea_endpoint->ep_join_id = 0;
3085 /* disconnect and select tone */
3086 new_state(EPOINT_STATE_OUT_DISCONNECT);
3087 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3088 /* if own_cause, we must release the join */
3089 if (e_ext.own_cause /* own cause */
3090 || !e_join_pattern) { /* no patterns */
3091 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);
3092 if (message_type != MESSAGE_RELEASE)
3093 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3095 } else { /* else we enable audio */
3096 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3097 message->param.audiopath = 1;
3098 message_put(message);
3100 /* send disconnect message */
3101 SCPY(e_tone, cause);
3102 portlist = ea_endpoint->ep_portlist;
3104 set_tone(portlist, cause);
3105 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3106 portlist = portlist->next;
3110 /* join MESSAGE_SETUP */
3111 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3113 struct lcr_msg *message;
3114 // struct interface *interface;
3116 /* if we already in setup state, we just update the dialing with new digits */
3117 if (e_state == EPOINT_STATE_OUT_SETUP
3118 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3119 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3120 /* if digits changed, what we have already dialed */
3121 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3122 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);
3123 /* release all ports */
3124 while((portlist = ea_endpoint->ep_portlist)) {
3125 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3126 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3127 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3128 message_put(message);
3129 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3130 ea_endpoint->free_portlist(portlist);
3133 /* disconnect audio */
3134 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3135 message->param.audiopath = 0;
3136 message_put(message);
3138 /* get dialing info */
3139 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3140 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3141 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3142 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3143 new_state(EPOINT_STATE_OUT_OVERLAP);
3146 schedule_timer(&e_redial_timeout, 1, 0);
3149 /* if we have a pending redial, so we just adjust the dialing number */
3150 if (e_redial_timeout.active) {
3151 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);
3152 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3155 if (!ea_endpoint->ep_portlist) {
3156 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3158 if (ea_endpoint->ep_portlist->next) {
3159 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3161 if (e_state == EPOINT_STATE_OUT_SETUP) {
3163 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);
3164 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3167 /* get what we have not dialed yet */
3168 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));
3169 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3170 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3171 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3172 message_put(message);
3173 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3175 /* always store what we have dialed or queued */
3176 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3180 if (e_state != EPOINT_STATE_IDLE) {
3181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3184 /* if an internal extension is dialed, copy that number */
3185 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3186 SCPY(e_ext.number, param->setup.dialinginfo.id);
3187 /* if an internal extension is dialed, get extension's info about caller */
3188 if (e_ext.number[0]) {
3189 if (!read_extension(&e_ext, e_ext.number)) {
3190 e_ext.number[0] = '\0';
3191 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3195 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3196 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3197 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3198 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3200 /* process (voice over) data calls */
3201 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3202 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3203 memset(&e_capainfo, 0, sizeof(e_capainfo));
3204 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3205 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3206 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3209 new_state(EPOINT_STATE_OUT_SETUP);
3210 /* call special setup routine */
3214 /* join MESSAGE_mISDNSIGNAL */
3215 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3217 struct lcr_msg *message;
3220 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3221 memcpy(&message->param, param, sizeof(union parameter));
3222 message_put(message);
3223 portlist = portlist->next;
3227 /* join MESSAGE_BRIDE */
3228 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3230 struct lcr_msg *message;
3233 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3234 memcpy(&message->param, param, sizeof(union parameter));
3235 message_put(message);
3236 portlist = portlist->next;
3240 /* join MESSAGE_NOTIFY */
3241 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3243 struct lcr_msg *message;
3246 if (param->notifyinfo.notify) {
3247 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3248 // /* if notification was generated locally, we turn hold music on/off */
3249 // if (param->notifyinfo.local)
3250 // 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)
3254 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3255 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3257 set_tone(portlist, "");
3258 portlist = portlist->next;
3261 portlist = ea_endpoint->ep_portlist;
3266 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3268 set_tone(portlist, "hold");
3269 portlist = portlist->next;
3271 portlist = ea_endpoint->ep_portlist;
3276 /* save new state */
3277 e_tx_state = new_state;
3280 /* notify port(s) about it */
3282 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3283 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3284 /* handle restricted caller ids */
3285 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3286 /* display callerid if desired for extension */
3287 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));
3288 message_put(message);
3289 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3290 portlist = portlist->next;
3294 /* join MESSAGE_DTMF */
3295 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3297 struct lcr_msg *message;
3300 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3301 memcpy(&message->param, param, sizeof(union parameter));
3302 message_put(message);
3303 portlist = portlist->next;
3307 /* JOIN sends messages to the endpoint
3309 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3311 struct port_list *portlist;
3312 struct lcr_msg *message;
3315 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3319 portlist = ea_endpoint->ep_portlist;
3321 // 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);
3322 switch(message_type) {
3323 /* JOIN SENDS TONE message */
3325 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);
3326 set_tone(portlist, param->tone.name);
3329 /* JOIN SENDS CRYPT message */
3331 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);
3332 join_crypt(portlist, message_type, param);
3335 /* JOIN sends INFORMATION message */
3336 case MESSAGE_INFORMATION:
3337 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);
3338 join_information(portlist, message_type, param);
3341 /* JOIN sends FACILITY message */
3342 case MESSAGE_FACILITY:
3343 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);
3344 join_facility(portlist, message_type, param);
3347 /* JOIN sends OVERLAP message */
3348 case MESSAGE_OVERLAP:
3349 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);
3350 if (e_state!=EPOINT_STATE_IN_SETUP
3351 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3352 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3355 join_overlap(portlist, message_type, param);
3358 /* JOIN sends PROCEEDING message */
3359 case MESSAGE_PROCEEDING:
3360 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);
3361 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3362 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3365 join_proceeding(portlist, message_type, param);
3368 /* JOIN sends ALERTING message */
3369 case MESSAGE_ALERTING:
3370 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);
3371 if (e_state!=EPOINT_STATE_IN_OVERLAP
3372 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3373 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3376 join_alerting(portlist, message_type, param);
3379 /* JOIN sends CONNECT message */
3380 case MESSAGE_CONNECT:
3381 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);
3382 if (e_state!=EPOINT_STATE_IN_OVERLAP
3383 && e_state!=EPOINT_STATE_IN_PROCEEDING
3384 && e_state!=EPOINT_STATE_IN_ALERTING) {
3385 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3388 join_connect(portlist, message_type, param);
3391 /* JOIN sends DISCONNECT/RELEASE message */
3392 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3393 case MESSAGE_RELEASE: /* JOIN releases */
3394 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);
3395 join_disconnect_release(message_type, param);
3398 /* JOIN sends SETUP message */
3400 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);
3401 join_setup(portlist, message_type, param);
3404 /* JOIN sends special mISDNSIGNAL message */
3405 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3406 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);
3407 join_mISDNsignal(portlist, message_type, param);
3410 /* JOIN sends bridge message */
3411 case MESSAGE_BRIDGE: /* bride message to port */
3412 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bridge message.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3413 join_bridge(portlist, message_type, param);
3416 /* JOIN has pattern available */
3417 case MESSAGE_PATTERN: /* indicating pattern available */
3418 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);
3419 if (!e_join_pattern) {
3420 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3424 set_tone(portlist, NULL);
3425 portlist = portlist->next;
3427 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3428 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3429 message->param.audiopath = 1;
3430 message_put(message);
3434 /* JOIN has no pattern available */
3435 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3436 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);
3437 if (e_join_pattern) {
3438 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3440 /* disconnect our audio tx and rx */
3441 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3442 message->param.audiopath = 0;
3443 message_put(message);
3448 /* JOIN (dunno at the moment) */
3449 case MESSAGE_REMOTE_AUDIO:
3450 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);
3451 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3452 message->param.audiopath = param->channel;
3453 message_put(message);
3457 /* JOIN sends a notify message */
3458 case MESSAGE_NOTIFY:
3459 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);
3460 join_notify(portlist, message_type, param);
3463 /* JOIN wants keypad / dtmf */
3464 case MESSAGE_ENABLEKEYPAD:
3465 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);
3468 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3472 /* JOIN sends a DTMF message */
3474 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);
3475 join_dtmf(portlist, message_type, param);
3479 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);
3484 /* pick_join will connect the first incoming call found. the endpoint
3485 * will receivce a MESSAGE_CONNECT.
3487 int match_list(char *list, char *item)
3489 char *end, *next = NULL;
3491 /* no list make matching */
3496 /* eliminate white spaces */
3497 while (*list > '\0' && *list <= ' ')
3503 /* if end of list is reached, we return */
3504 if (list[0] == '\0')
3506 /* if we have more than one entry (left) */
3507 if ((end = strchr(list, ',')))
3510 next = end = strchr(list, '\0');
3511 while (*(end-1) <= ' ')
3513 /* if string part matches item */
3514 if (!strncmp(list, item, end-list))
3520 void EndpointAppPBX::pick_join(char *extensions)
3522 struct lcr_msg *message;
3523 struct port_list *portlist;
3525 class EndpointAppPBX *eapp, *found;
3527 class JoinPBX *joinpbx;
3528 struct join_relation *relation;
3531 /* find an endpoint that is ringing internally or vbox with higher priority */
3534 eapp = apppbx_first;
3536 if (eapp!=this && ea_endpoint->ep_portlist) {
3537 portlist = eapp->ea_endpoint->ep_portlist;
3539 if ((port = find_port_id(portlist->port_id))) {
3540 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3541 if (match_list(extensions, eapp->e_ext.number)) {
3547 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3548 && port->p_state==PORT_STATE_OUT_ALERTING)
3549 if (match_list(extensions, eapp->e_ext.number)) {
3553 portlist = portlist->next;
3561 /* if no endpoint found */
3563 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);
3565 set_tone(ea_endpoint->ep_portlist, "cause_10");
3566 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3567 new_state(EPOINT_STATE_OUT_DISCONNECT);
3572 if (ea_endpoint->ep_join_id) {
3573 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3576 if (!eapp->ea_endpoint->ep_join_id) {
3577 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3580 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3582 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3585 if (join->j_type != JOIN_TYPE_PBX) {
3586 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3589 joinpbx = (class JoinPBX *)join;
3590 relation = joinpbx->j_relation;
3592 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3595 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3596 relation = relation->next;
3598 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3603 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3605 if (options.deb & DEBUG_EPOINT) {
3606 class Join *debug_c = join_first;
3607 class Endpoint *debug_e = epoint_first;
3608 class Port *debug_p = port_first;
3610 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3612 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3614 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3615 debug_c = debug_c->next;
3617 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3619 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3620 debug_e = debug_e->next;
3622 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3624 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3625 debug_p = debug_p->next;
3630 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3631 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3632 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3634 /* connnecting our endpoint */
3635 new_state(EPOINT_STATE_CONNECT);
3636 if (e_ext.number[0])
3638 set_tone(ea_endpoint->ep_portlist, NULL);
3640 /* now we send a release to the ringing endpoint */
3641 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3642 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3643 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3644 message_put(message);
3646 /* we send a connect to the join with our caller id */
3647 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3648 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3649 message->param.connectinfo.present = e_callerinfo.present;
3650 message->param.connectinfo.screen = e_callerinfo.screen;
3651 message->param.connectinfo.itype = e_callerinfo.itype;
3652 message->param.connectinfo.ntype = e_callerinfo.ntype;
3653 message_put(message);
3655 /* we send a connect to our port with the remote callerid */
3656 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3657 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3658 message->param.connectinfo.present = eapp->e_callerinfo.present;
3659 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3660 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3661 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3662 /* handle restricted caller ids */
3663 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);
3664 /* display callerid if desired for extension */
3665 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));
3666 message_put(message);
3668 /* we send a connect to the audio path (not for vbox) */
3669 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3670 message->param.audiopath = 1;
3671 message_put(message);
3673 /* beeing paranoid, we make call update */
3674 trigger_work(&joinpbx->j_updatebridge);
3676 if (options.deb & DEBUG_EPOINT) {
3677 class Join *debug_c = join_first;
3678 class Endpoint *debug_e = epoint_first;
3679 class Port *debug_p = port_first;
3681 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3683 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3685 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3686 debug_c = debug_c->next;
3688 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3690 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3691 debug_e = debug_e->next;
3693 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3695 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3696 debug_p = debug_p->next;
3702 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3704 void EndpointAppPBX::join_join(void)
3706 struct lcr_msg *message;
3707 struct join_relation *our_relation, *other_relation;
3708 struct join_relation **our_relation_pointer, **other_relation_pointer;
3709 class Join *our_join, *other_join;
3710 class JoinPBX *our_joinpbx, *other_joinpbx;
3711 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3712 class Port *our_port, *other_port;
3713 class Pdss1 *our_pdss1, *other_pdss1;
3715 /* are we a candidate to join a join? */
3716 our_join = find_join_id(ea_endpoint->ep_join_id);
3718 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3721 if (our_join->j_type != JOIN_TYPE_PBX) {
3722 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3725 our_joinpbx = (class JoinPBX *)our_join;
3726 if (!ea_endpoint->ep_portlist) {
3727 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3730 if (!e_ext.number[0]) {
3731 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3734 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3736 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3739 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3740 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3743 our_pdss1 = (class Pdss1 *)our_port;
3745 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3746 other_eapp = apppbx_first;
3748 if (other_eapp == this) {
3749 other_eapp = other_eapp->next;
3752 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);
3753 if (other_eapp->e_ext.number[0] /* has terminal */
3754 && other_eapp->ea_endpoint->ep_portlist /* has port */
3755 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3756 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3757 if (other_port) { /* port still exists */
3758 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3759 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3760 other_pdss1 = (class Pdss1 *)other_port;
3761 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);
3762 if (other_pdss1->p_m_hold /* port is on hold */
3763 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3764 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3767 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3770 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3773 other_eapp = other_eapp->next;
3776 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3779 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3781 /* if we have the same join */
3782 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3783 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3786 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3788 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3791 if (other_join->j_type != JOIN_TYPE_PBX) {
3792 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3795 other_joinpbx = (class JoinPBX *)other_join;
3796 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3797 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3801 /* remove relation to endpoint for join on hold */
3802 other_relation = other_joinpbx->j_relation;
3803 other_relation_pointer = &other_joinpbx->j_relation;
3804 while(other_relation) {
3805 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3806 /* detach other endpoint on hold */
3807 *other_relation_pointer = other_relation->next;
3808 FREE(other_relation, sizeof(struct join_relation));
3810 other_relation = *other_relation_pointer;
3811 other_eapp->ea_endpoint->ep_join_id = 0;
3815 /* change join/hold pointer of endpoint to the new join */
3816 temp_epoint = find_epoint_id(other_relation->epoint_id);
3818 if (temp_epoint->ep_join_id == other_join->j_serial)
3819 temp_epoint->ep_join_id = our_join->j_serial;
3822 other_relation_pointer = &other_relation->next;
3823 other_relation = other_relation->next;
3825 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3827 /* join call relations */
3828 our_relation = our_joinpbx->j_relation;
3829 our_relation_pointer = &our_joinpbx->j_relation;
3830 while(our_relation) {
3831 our_relation_pointer = &our_relation->next;
3832 our_relation = our_relation->next;
3834 *our_relation_pointer = other_joinpbx->j_relation;
3835 other_joinpbx->j_relation = NULL;
3836 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3838 /* release endpoint on hold */
3839 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3840 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3841 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3842 message_put(message);
3844 /* if we are not a partyline, we get partyline state from other join */
3845 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3847 /* remove empty join */
3849 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3851 /* mixer must update */
3852 trigger_work(&our_joinpbx->j_updatebridge);
3854 /* we send a retrieve to that endpoint */
3855 // mixer will update the hold-state of the join and send it to the endpoints is changes
3859 /* check if we have an external call
3860 * this is used to check for encryption ability
3862 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3864 struct join_relation *relation;
3866 class JoinPBX *joinpbx;
3867 class Endpoint *epoint;
3869 /* some paranoia check */
3870 if (!ea_endpoint->ep_portlist) {
3871 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3872 *errstr = "No Call";
3875 if (!e_ext.number[0]) {
3876 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3877 *errstr = "No Call";
3881 /* check if we have a join with 2 parties */
3882 join = find_join_id(ea_endpoint->ep_join_id);
3884 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3885 *errstr = "No Call";
3888 if (join->j_type != JOIN_TYPE_PBX) {
3889 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3890 *errstr = "No PBX Call";
3893 joinpbx = (class JoinPBX *)join;
3894 relation = joinpbx->j_relation;
3896 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3897 *errstr = "No Call";
3900 if (!relation->next) {
3901 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3902 *errstr = "No Call";
3905 if (relation->next->next) {
3906 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3907 *errstr = "Err: Conference";
3910 if (relation->epoint_id == ea_endpoint->ep_serial) {
3911 relation = relation->next;
3912 if (relation->epoint_id == ea_endpoint->ep_serial) {
3913 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3914 *errstr = "Software Error";
3919 /* check remote port for external call */
3920 epoint = find_epoint_id(relation->epoint_id);
3922 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3923 *errstr = "No Call";
3926 if (!epoint->ep_portlist) {
3927 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3928 *errstr = "No Call";
3931 *port = find_port_id(epoint->ep_portlist->port_id);
3933 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3934 *errstr = "No Call";
3937 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
3938 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3939 *errstr = "No Ext Call";
3942 if ((*port)->p_state != PORT_STATE_CONNECT) {
3943 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3944 *errstr = "No Ext Connect";
3950 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3952 const char *logtext = "unknown";
3955 switch(message_type) {
3957 trace_header("SETUP", dir);
3958 if (dir == DIRECTION_OUT)
3959 add_trace("to", NULL, "CH(%lu)", port_id);
3960 if (dir == DIRECTION_IN)
3961 add_trace("from", NULL, "CH(%lu)", port_id);
3962 if (param->setup.callerinfo.extension[0])
3963 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3964 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3965 switch(param->setup.callerinfo.present) {
3966 case INFO_PRESENT_RESTRICTED:
3967 add_trace("caller id", "present", "restricted");
3969 case INFO_PRESENT_ALLOWED:
3970 add_trace("caller id", "present", "allowed");
3973 add_trace("caller id", "present", "not available");
3975 if (param->setup.callerinfo.ntype2) {
3976 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3977 switch(param->setup.callerinfo.present) {
3978 case INFO_PRESENT_RESTRICTED:
3979 add_trace("caller id2", "present", "restricted");
3981 case INFO_PRESENT_ALLOWED:
3982 add_trace("caller id2", "present", "allowed");
3985 add_trace("caller id2", "present", "not available");
3988 if (param->setup.redirinfo.id[0]) {
3989 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3990 switch(param->setup.redirinfo.present) {
3991 case INFO_PRESENT_RESTRICTED:
3992 add_trace("redir'ing", "present", "restricted");
3994 case INFO_PRESENT_ALLOWED:
3995 add_trace("redir'ing", "present", "allowed");
3998 add_trace("redir'ing", "present", "not available");
4001 if (param->setup.dialinginfo.id[0])
4002 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4003 if (param->setup.dialinginfo.keypad[0])
4004 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4005 if (param->setup.dialinginfo.display[0])
4006 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4007 if (param->setup.dialinginfo.sending_complete)
4008 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4012 case MESSAGE_OVERLAP:
4013 trace_header("SETUP ACKNOWLEDGE", dir);
4014 if (dir == DIRECTION_OUT)
4015 add_trace("to", NULL, "CH(%lu)", port_id);
4016 if (dir == DIRECTION_IN)
4017 add_trace("from", NULL, "CH(%lu)", port_id);
4021 case MESSAGE_PROCEEDING:
4022 trace_header("PROCEEDING", dir);
4023 if (dir == DIRECTION_OUT)
4024 add_trace("to", NULL, "CH(%lu)", port_id);
4025 if (dir == DIRECTION_IN)
4026 add_trace("from", NULL, "CH(%lu)", port_id);
4030 case MESSAGE_ALERTING:
4031 trace_header("ALERTING", dir);
4032 if (dir == DIRECTION_OUT)
4033 add_trace("to", NULL, "CH(%lu)", port_id);
4034 if (dir == DIRECTION_IN)
4035 add_trace("from", NULL, "CH(%lu)", port_id);
4039 case MESSAGE_CONNECT:
4040 trace_header("CONNECT", dir);
4041 if (dir == DIRECTION_OUT)
4042 add_trace("to", NULL, "CH(%lu)", port_id);
4043 if (dir == DIRECTION_IN)
4044 add_trace("from", NULL, "CH(%lu)", port_id);
4045 if (param->connectinfo.extension[0])
4046 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4047 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4048 switch(param->connectinfo.present) {
4049 case INFO_PRESENT_RESTRICTED:
4050 add_trace("connect id", "present", "restricted");
4052 case INFO_PRESENT_ALLOWED:
4053 add_trace("connect id", "present", "allowed");
4056 add_trace("connect id", "present", "not available");
4058 if (param->connectinfo.display[0])
4059 add_trace("display", NULL, "%s", param->connectinfo.display);
4063 case MESSAGE_DISCONNECT:
4064 case MESSAGE_RELEASE:
4065 if (message_type == MESSAGE_DISCONNECT)
4066 trace_header("DISCONNECT", dir);
4068 trace_header("RELEASE", dir);
4069 if (dir == DIRECTION_OUT)
4070 add_trace("to", NULL, "CH(%lu)", port_id);
4071 if (dir == DIRECTION_IN)
4072 add_trace("from", NULL, "CH(%lu)", port_id);
4073 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4074 switch(param->disconnectinfo.location) {
4076 add_trace("cause", "location", "0-User");
4078 case LOCATION_PRIVATE_LOCAL:
4079 add_trace("cause", "location", "1-Local-PBX");
4081 case LOCATION_PUBLIC_LOCAL:
4082 add_trace("cause", "location", "2-Local-Exchange");
4084 case LOCATION_TRANSIT:
4085 add_trace("cause", "location", "3-Transit");
4087 case LOCATION_PUBLIC_REMOTE:
4088 add_trace("cause", "location", "4-Remote-Exchange");
4090 case LOCATION_PRIVATE_REMOTE:
4091 add_trace("cause", "location", "5-Remote-PBX");
4093 case LOCATION_INTERNATIONAL:
4094 add_trace("cause", "location", "7-International-Exchange");
4096 case LOCATION_BEYOND:
4097 add_trace("cause", "location", "10-Beyond-Interworking");
4100 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4102 if (param->disconnectinfo.display[0])
4103 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4107 case MESSAGE_NOTIFY:
4108 switch(param->notifyinfo.notify) {
4113 logtext = "USER_SUSPENDED";
4116 logtext = "BEARER_SERVICE_CHANGED";
4119 logtext = "USER_RESUMED";
4122 logtext = "CONFERENCE_ESTABLISHED";
4125 logtext = "CONFERENCE_DISCONNECTED";
4128 logtext = "OTHER_PARTY_ADDED";
4131 logtext = "ISOLATED";
4134 logtext = "REATTACHED";
4137 logtext = "OTHER_PARTY_ISOLATED";
4140 logtext = "OTHER_PARTY_REATTACHED";
4143 logtext = "OTHER_PARTY_SPLIT";
4146 logtext = "OTHER_PARTY_DISCONNECTED";
4149 logtext = "CONFERENCE_FLOATING";
4152 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4155 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4158 logtext = "CALL_IS_A_WAITING_CALL";
4161 logtext = "DIVERSION_ACTIVATED";
4164 logtext = "RESERVED_CT_1";
4167 logtext = "RESERVED_CT_2";
4170 logtext = "REVERSE_CHARGING";
4173 logtext = "REMOTE_HOLD";
4176 logtext = "REMOTE_RETRIEVAL";
4179 logtext = "CALL_IS_DIVERTING";
4182 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4186 trace_header("NOTIFY", dir);
4187 if (dir == DIRECTION_OUT)
4188 add_trace("to", NULL, "CH(%lu)", port_id);
4189 if (dir == DIRECTION_IN)
4190 add_trace("from", NULL, "CH(%lu)", port_id);
4191 if (param->notifyinfo.notify)
4192 add_trace("indicator", NULL, "%s", logtext);
4193 if (param->notifyinfo.id[0]) {
4194 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4195 switch(param->notifyinfo.present) {
4196 case INFO_PRESENT_RESTRICTED:
4197 add_trace("redir'on", "present", "restricted");
4199 case INFO_PRESENT_ALLOWED:
4200 add_trace("redir'on", "present", "allowed");
4203 add_trace("redir'on", "present", "not available");
4206 if (param->notifyinfo.display[0])
4207 add_trace("display", NULL, "%s", param->notifyinfo.display);
4211 case MESSAGE_PROGRESS:
4212 switch(param->progressinfo.progress) {
4214 logtext = "Call is not end to end ISDN";
4217 logtext = "Destination address is non-ISDN";
4220 logtext = "Origination address is non-ISDN";
4223 logtext = "Call has returned to the ISDN";
4226 logtext = "In-band info or pattern available";
4229 SPRINT(buffer, "%d", param->progressinfo.progress);
4233 trace_header("PROGRESS", dir);
4234 if (dir == DIRECTION_OUT)
4235 add_trace("to", NULL, "CH(%lu)", port_id);
4236 if (dir == DIRECTION_IN)
4237 add_trace("from", NULL, "CH(%lu)", port_id);
4238 add_trace("indicator", NULL, "%s", logtext);
4239 switch(param->progressinfo.location) {
4241 add_trace("cause", "location", "0-User");
4243 case LOCATION_PRIVATE_LOCAL:
4244 add_trace("cause", "location", "1-Local-PBX");
4246 case LOCATION_PUBLIC_LOCAL:
4247 add_trace("cause", "location", "2-Local-Exchange");
4249 case LOCATION_TRANSIT:
4250 add_trace("cause", "location", "3-Transit");
4252 case LOCATION_PUBLIC_REMOTE:
4253 add_trace("cause", "location", "4-Remote-Exchange");
4255 case LOCATION_PRIVATE_REMOTE:
4256 add_trace("cause", "location", "5-Remote-PBX");
4258 case LOCATION_INTERNATIONAL:
4259 add_trace("cause", "location", "7-International-Exchange");
4261 case LOCATION_BEYOND:
4262 add_trace("cause", "location", "10-Beyond-Interworking");
4265 add_trace("cause", "location", "%d", param->progressinfo.location);
4270 case MESSAGE_INFORMATION:
4271 trace_header("INFORMATION", dir);
4272 if (dir == DIRECTION_OUT)
4273 add_trace("to", NULL, "CH(%lu)", port_id);
4274 if (dir == DIRECTION_IN)
4275 add_trace("from", NULL, "CH(%lu)", port_id);
4276 if (param->information.id[0])
4277 add_trace("dialing", NULL, "%s", param->information.id);
4278 if (param->information.display[0])
4279 add_trace("display", NULL, "%s", param->information.display);
4280 if (param->information.sending_complete)
4281 add_trace("complete", NULL, "true", param->information.sending_complete);
4285 case MESSAGE_FACILITY:
4286 trace_header("FACILITY", 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);
4295 trace_header("TONE", dir);
4296 if (dir == DIRECTION_OUT)
4297 add_trace("to", NULL, "CH(%lu)", port_id);
4298 if (dir == DIRECTION_IN)
4299 add_trace("from", NULL, "CH(%lu)", port_id);
4300 if (param->tone.name[0]) {
4301 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4302 add_trace("name", NULL, "%s", param->tone.name);
4304 add_trace("off", NULL, NULL);
4308 case MESSAGE_SUSPEND:
4309 case MESSAGE_RESUME:
4310 if (message_type == MESSAGE_SUSPEND)
4311 trace_header("SUSPEND", dir);
4313 trace_header("RESUME", dir);
4314 if (dir == DIRECTION_OUT)
4315 add_trace("to", NULL, "CH(%lu)", port_id);
4316 if (dir == DIRECTION_IN)
4317 add_trace("from", NULL, "CH(%lu)", port_id);
4318 if (param->parkinfo.len)
4319 add_trace("length", NULL, "%d", param->parkinfo.len);
4324 case MESSAGE_BCHANNEL:
4325 trace_header("BCHANNEL", dir);
4326 switch(param->bchannel.type) {
4327 case BCHANNEL_REQUEST:
4328 add_trace("type", NULL, "request");
4330 case BCHANNEL_ASSIGN:
4331 add_trace("type", NULL, "assign");
4333 case BCHANNEL_ASSIGN_ACK:
4334 add_trace("type", NULL, "assign_ack");
4336 case BCHANNEL_REMOVE:
4337 add_trace("type", NULL, "remove");
4339 case BCHANNEL_REMOVE_ACK:
4340 add_trace("type", NULL, "remove_ack");
4343 if (param->bchannel.addr)
4344 add_trace("address", NULL, "%x", param->bchannel.addr);
4350 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4354 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4356 struct lcr_msg *message;
4360 if (!portlist->port_id)
4363 if (!e_connectedmode) {
4364 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4365 message->param.disconnectinfo.cause = cause;
4366 message->param.disconnectinfo.location = location;
4368 SCPY(message->param.disconnectinfo.display, display);
4370 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4372 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4374 SCPY(message->param.notifyinfo.display, display);
4376 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4378 message_put(message);
4379 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);