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(void)
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;
855 /* set bchannel mode */
856 mode = e_capainfo.source_mode;
858 /* create settings for creating port */
859 memset(&port_settings, 0, sizeof(port_settings));
861 SCPY(port_settings.tones_dir, e_ext.tones_dir);
863 SCPY(port_settings.tones_dir, options.tones_dir);
864 port_settings.no_seconds = e_ext.no_seconds;
866 /* 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 */
868 /* check what dialinginfo.itype we got */
869 switch(e_dialinginfo.itype) {
870 /* *********************** call to extension or vbox */
871 case INFO_ITYPE_ISDN_EXTENSION:
872 /* check if we deny incoming calls when we use an extension */
873 if (e_ext.noknocking) {
874 atemp = apppbx_first;
877 if (!strcmp(atemp->e_ext.number, e_ext.number))
882 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
883 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
884 return; /* must exit here */
887 /* FALL THROUGH !!!! */
888 case INFO_ITYPE_VBOX:
889 /* get dialed extension's info */
890 // SCPY(exten, e_dialinginfo.id);
891 // if (strchr(exten, ','))
892 // *strchr(exten, ',') = '\0';
893 // if (!read_extension(&e_ext, exten))
894 if (!read_extension(&e_ext, e_dialinginfo.id)) {
895 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
896 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
897 return; /* must exit here */
899 e_dialinginfo.sending_complete = 1;
901 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
902 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
907 /* string from unconditional call forward (cfu) */
910 /* present to forwarded party */
911 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
912 e_callerinfo.present = INFO_PRESENT_ALLOWED;
914 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
918 /* string from busy call forward (cfb) */
921 class EndpointAppPBX *checkapp = apppbx_first;
923 if (checkapp != this) { /* any other endpoint except our own */
924 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
925 /* present to forwarded party */
926 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
927 e_callerinfo.present = INFO_PRESENT_ALLOWED;
929 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
933 checkapp = checkapp->next;
937 /* string from no-response call forward (cfnr) */
940 /* when cfnr is done, out_setup() will setup the call */
941 if (e_cfnr_call_timeout.active) {
942 /* present to forwarded party */
943 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
944 e_callerinfo.present = INFO_PRESENT_ALLOWED;
948 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
949 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
950 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
951 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);
955 /* call to all internal interfaces */
956 p = e_ext.interfaces;
957 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
960 while(*p!=',' && *p!='\0')
965 /* found interface */
966 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
967 /* hunt for mISDNport and create Port */
968 mISDNport = hunt_port(ifname, &channel);
970 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
971 add_trace("interface", NULL, "%s", ifname);
975 /* creating INTERNAL port */
976 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
979 port = ss5_hunt_line(mISDNport);
983 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);
986 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
991 FATAL("No memory for Port instance\n");
992 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
993 memset(&dialinginfo, 0, sizeof(dialinginfo));
994 SCPY(dialinginfo.id, e_dialinginfo.id);
995 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
996 dialinginfo.ntype = e_dialinginfo.ntype;
997 /* create port_list relation */
998 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1000 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1002 goto check_anycall_intern;
1004 /* directory.list */
1005 if (e_callerinfo.id[0] && e_ext.display_name) {
1006 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1008 SCPY(e_callerinfo.name, dirname);
1010 // dss1 = (class Pdss1 *)port;
1012 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1013 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1014 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1015 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1016 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1017 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1018 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1019 //terminal if (e_dialinginfo.id)
1020 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1021 /* handle restricted caller ids */
1022 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);
1023 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);
1024 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);
1025 /* display callerid if desired for extension */
1026 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));
1027 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1028 /* use cnip, if enabld */
1029 // if (!e_ext.centrex)
1030 // message->param.setup.callerinfo.name[0] = '\0';
1031 /* screen clip if prefix is required */
1032 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1033 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1034 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1035 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1037 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1038 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1039 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1040 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1042 /* use internal caller id */
1043 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1044 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1045 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1046 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1048 message_put(message);
1049 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1053 /* string from parallel call forward (cfp) */
1056 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1057 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1058 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1062 vbox_only: /* entry point for answering machine only */
1063 cfu_only: /* entry point for cfu */
1064 cfb_only: /* entry point for cfb */
1065 cfnr_only: /* entry point for cfnr */
1066 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1070 /* only if vbox should be dialed, and terminal is given */
1071 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1072 /* go to the end of p */
1075 /* answering vbox call */
1076 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1078 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1079 FATAL("No memory for VBOX Port instance\n");
1080 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1081 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1084 while(*p!=',' && *p!='\0')
1089 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1090 /* hunt for mISDNport and create Port */
1091 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1093 /* creating EXTERNAL port*/
1094 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1097 port = ss5_hunt_line(mISDNport);
1100 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);
1102 FATAL("No memory for Port instance\n");
1103 earlyb = mISDNport->earlyb;
1106 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1107 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1112 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1113 goto check_anycall_intern;
1115 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1116 memset(&dialinginfo, 0, sizeof(dialinginfo));
1117 SCPY(dialinginfo.id, cfp);
1118 dialinginfo.itype = INFO_ITYPE_ISDN;
1119 dialinginfo.ntype = e_dialinginfo.ntype;
1120 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1122 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1124 goto check_anycall_intern;
1126 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1127 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1128 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1129 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1130 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1131 /* if clip is hidden */
1132 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1133 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1134 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1135 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1136 message->param.setup.callerinfo.present = e_ext.callerid_present;
1137 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1139 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1140 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1141 //terminal if (e_dialinginfo.id)
1142 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1143 /* handle restricted caller ids */
1144 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);
1145 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);
1146 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);
1147 /* display callerid if desired for extension */
1148 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));
1149 message_put(message);
1150 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1154 check_anycall_intern:
1155 /* now we have all ports created */
1157 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1159 if (!ea_endpoint->ep_join_id)
1161 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1162 return; /* must exit here */
1166 /* *********************** external call */
1168 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1169 /* call to extenal interfaces */
1170 if (e_dialinginfo.keypad[0])
1171 p = e_dialinginfo.keypad;
1173 p = e_dialinginfo.id;
1176 while(*p!=',' && *p!='\0')
1177 SCCAT(number, *p++);
1181 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");
1182 /* hunt for mISDNport and create Port */
1183 /* hunt for mISDNport and create Port */
1184 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1186 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1187 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1189 goto check_anycall_extern;
1191 /* creating EXTERNAL port*/
1192 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1195 port = ss5_hunt_line(mISDNport);
1198 if (!mISDNport->gsm)
1199 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);
1202 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1207 FATAL("No memory for Port instance\n");
1208 earlyb = mISDNport->earlyb;
1209 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1210 memset(&dialinginfo, 0, sizeof(dialinginfo));
1211 if (e_dialinginfo.keypad[0])
1212 SCPY(dialinginfo.keypad, number);
1214 SCPY(dialinginfo.id, number);
1215 dialinginfo.itype = INFO_ITYPE_ISDN;
1216 dialinginfo.ntype = e_dialinginfo.ntype;
1217 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1218 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1220 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1222 goto check_anycall_extern;
1224 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1225 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1226 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1227 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1228 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1229 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1230 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1231 //terminal if (e_dialinginfo.id)
1232 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1233 /* handle restricted caller ids */
1234 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);
1235 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);
1236 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);
1237 /* display callerid if desired for extension */
1238 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));
1239 message_put(message);
1240 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1244 check_anycall_extern:
1245 /* now we have all ports created */
1247 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1249 if (!ea_endpoint->ep_join_id)
1251 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1252 return; /* must exit here */
1259 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1261 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1263 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1266 unsched_timer(&ea->e_redial_timeout);
1267 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1268 ea->e_multipoint_cause = 0;
1269 ea->e_multipoint_location = 0;
1270 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1271 ea->e_join_pattern = 0;
1272 ea->process_dialing(1);
1273 /* we must exit, because our endpoint might be gone */
1278 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1280 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1282 if (!ea->e_action) {
1283 unsched_timer(&ea->e_redial_timeout);
1284 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1285 ea->process_dialing(0);
1286 /* we must exit, because our endpoint might be gone */
1292 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1294 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1296 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1298 ea->new_state(EPOINT_STATE_OUT_SETUP);
1299 /* call special setup routine */
1305 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1307 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1309 /* leave power dialing on */
1310 ea->e_powerdial_on = 1;
1311 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1314 ea->e_ruleset = ruleset_main;
1316 ea->e_rule = ea->e_ruleset->rule_first;
1317 ea->e_action = NULL;
1318 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1319 ea->process_dialing(0);
1324 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1326 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1327 struct port_list *portlist;
1328 struct lcr_msg *message;
1330 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1332 /* release all ports */
1333 while((portlist = ea->ea_endpoint->ep_portlist)) {
1334 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1335 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1336 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1337 message_put(message);
1338 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1339 ea->ea_endpoint->free_portlist(portlist);
1342 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1343 message->param.audiopath = 0;
1344 message_put(message);
1345 /* indicate no patterns */
1346 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1347 message_put(message);
1348 /* set setup state, since we have no response from the new join */
1349 ea->new_state(EPOINT_STATE_OUT_SETUP);
1354 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1356 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1358 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);
1364 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1366 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1368 if (ea->e_state == EPOINT_STATE_IDLE) {
1369 /* epoint is idle, check callback */
1370 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1371 ea->new_state(EPOINT_STATE_OUT_SETUP);
1378 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1380 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1382 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1383 struct port_list *portlist;
1385 ea->e_ruleset = ruleset_main;
1387 ea->e_rule = ea->e_ruleset->rule_first;
1388 ea->e_action = NULL;
1389 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1390 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1392 ea->e_connectedmode = 0;
1394 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1395 portlist = ea->ea_endpoint->ep_portlist;
1397 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1398 ea->set_tone(portlist, "cause_10");
1405 /* doing a hookflash */
1406 void EndpointAppPBX::hookflash(void)
1411 /* be sure that we are active */
1413 e_tx_state = NOTIFY_STATE_ACTIVE;
1415 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1417 if (ea_endpoint->ep_use > 1) {
1418 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1421 /* dialtone after pressing the hash key */
1422 process_hangup(e_join_cause, e_join_location);
1423 e_multipoint_cause = 0;
1424 e_multipoint_location = 0;
1425 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1427 port->set_echotest(0);
1429 if (ea_endpoint->ep_join_id) {
1430 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1432 e_ruleset = ruleset_main;
1434 e_rule = e_ruleset->rule_first;
1436 new_state(EPOINT_STATE_IN_OVERLAP);
1437 e_connectedmode = 1;
1438 SCPY(e_dialinginfo.id, e_ext.prefix);
1439 e_extdialing = e_dialinginfo.id;
1441 if (e_dialinginfo.id[0]) {
1442 set_tone(ea_endpoint->ep_portlist, "dialing");
1445 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1453 /* messages from port
1455 /* port MESSAGE_SETUP */
1456 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1458 struct lcr_msg *message;
1460 int writeext; /* flags need to write extension after modification */
1462 struct interface *interface;
1464 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1466 portlist->port_type = param->setup.port_type;
1467 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1468 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1469 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1470 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1472 /* convert (inter-)national number type */
1473 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1474 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1476 // e_dtmf = param->setup.dtmf;
1477 /* screen incoming caller id */
1478 interface = interface_first;
1480 if (!strcmp(e_callerinfo.interface, interface->name)) {
1483 interface = interface->next;
1486 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1487 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1490 /* process extension */
1491 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1492 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1493 /* port makes call from extension */
1494 SCPY(e_callerinfo.extension, e_callerinfo.id);
1495 SCPY(e_ext.number, e_callerinfo.extension);
1496 SCPY(e_extension_interface, e_callerinfo.interface);
1498 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1501 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1502 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1504 /* get extension's info about caller */
1505 if (!read_extension(&e_ext, e_ext.number)) {
1506 /* extension doesn't exist */
1507 trace_header("EXTENSION (not created)", DIRECTION_IN);
1508 add_trace("extension", NULL, "%s", e_ext.number);
1510 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1511 new_state(EPOINT_STATE_OUT_DISCONNECT);
1512 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1513 e_ext.number[0] = '\0'; /* no terminal */
1518 /* put prefix (next) in front of e_dialinginfo.id */
1519 if (e_ext.next[0]) {
1520 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1521 SCPY(e_dialinginfo.id, buffer);
1522 e_ext.next[0] = '\0';
1524 } else if (e_ext.prefix[0]) {
1525 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1526 SCPY(e_dialinginfo.id, buffer);
1529 /* screen caller id by extension's config */
1530 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1532 SCPY(e_callerinfo.name, e_ext.name);
1533 /* use caller id (or if exist: id_next_call) for this call */
1534 if (e_ext.id_next_call_present >= 0) {
1535 SCPY(e_callerinfo.id, e_ext.id_next_call);
1536 /* if we restrict the pesentation */
1537 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1538 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1539 else e_callerinfo.present = e_ext.id_next_call_present;
1540 e_callerinfo.ntype = e_ext.id_next_call_type;
1541 e_ext.id_next_call_present = -1;
1544 SCPY(e_callerinfo.id, e_ext.callerid);
1545 /* if we restrict the pesentation */
1546 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1547 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1548 else e_callerinfo.present = e_ext.callerid_present;
1549 e_callerinfo.ntype = e_ext.callerid_type;
1551 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1553 /* extension is written */
1555 write_extension(&e_ext, e_ext.number);
1557 /* set volume of rx and tx */
1558 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1559 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1560 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1561 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1562 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1563 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1564 message_put(message);
1567 /* start recording if enabled */
1568 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1569 /* check if we are a terminal */
1570 if (e_ext.number[0] == '\0')
1571 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1573 port = find_port_id(portlist->port_id);
1575 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1579 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1580 /* no terminal identification */
1581 e_ext.number[0] = '\0';
1582 e_extension_interface[0] = '\0';
1583 memset(&e_ext, 0, sizeof(e_ext));
1584 e_ext.rights = 4; /* right to dial internat */
1588 e_ruleset = ruleset_main;
1590 e_rule = e_ruleset->rule_first;
1592 e_extdialing = e_dialinginfo.id;
1593 new_state(EPOINT_STATE_IN_SETUP);
1594 if (e_dialinginfo.id[0]) {
1595 set_tone(portlist, "dialing");
1597 if (e_ext.number[0])
1598 set_tone(portlist, "dialpbx");
1600 set_tone(portlist, "dialtone");
1603 if (e_state == EPOINT_STATE_IN_SETUP) {
1604 /* request MORE info, if not already at higher state */
1605 new_state(EPOINT_STATE_IN_OVERLAP);
1606 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1607 message_put(message);
1608 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1612 /* port MESSAGE_INFORMATION */
1613 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1615 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1617 /* ignore information message without digit information */
1618 if (!param->information.id[0])
1623 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1625 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1630 /* if vbox_play is done, the information are just used as they come */
1632 if (e_action->index == ACTION_VBOX_PLAY) {
1633 /* concat dialing string */
1634 SCAT(e_dialinginfo.id, param->information.id);
1639 /* keypad when disconnect but in connected mode */
1640 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1641 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1642 /* processing keypad function */
1643 if (param->information.id[0] == '0') {
1649 /* keypad when connected */
1650 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1651 if (e_ext.keypad || e_enablekeypad) {
1652 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1653 /* processing keypad function */
1654 if (param->information.id[0] == '0') {
1657 if (param->information.id[0])
1658 keypad_function(param->information.id[0]);
1660 if (e_ext.number[0])
1661 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1663 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1668 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1669 if (e_ext.number[0])
1670 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1672 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1676 if (!param->information.id[0])
1678 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1679 set_tone(portlist, "dialing");
1682 if (e_action->index==ACTION_OUTDIAL
1683 || e_action->index==ACTION_EXTERNAL
1684 || e_action->index==ACTION_REMOTE) {
1686 set_tone(portlist, "dialing");
1687 else if (!e_extdialing[0])
1688 set_tone(portlist, "dialing");
1690 /* concat dialing string */
1691 SCAT(e_dialinginfo.id, param->information.id);
1695 /* port MESSAGE_DTMF */
1696 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1702 /* only if dtmf detection is enabled */
1704 trace_header("DTMF (disabled)", DIRECTION_IN);
1708 trace_header("DTMF", DIRECTION_IN);
1709 add_trace("digit", NULL, "%c", param->dtmf);
1713 NOTE: vbox is now handled due to overlap state
1714 /* if vbox_play is done, the dtmf digits are just used as they come */
1716 if (e_action->index == ACTION_VBOX_PLAY) {
1717 /* concat dialing string */
1718 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1719 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1720 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1723 /* continue to process *X# sequences */
1727 /* check for *X# sequence */
1728 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1729 if (e_dtmf_time+3 < now) {
1730 /* the last digit was too far in the past to be a sequence */
1731 if (param->dtmf == '*')
1732 /* only start is allowed in the sequence */
1737 /* we have a sequence of digits, see what we got */
1738 if (param->dtmf == '*')
1740 else if (param->dtmf>='0' && param->dtmf<='9') {
1741 /* we need to have a star before we receive the digit of the sequence */
1742 if (e_dtmf_last == '*')
1743 e_dtmf_last = param->dtmf;
1744 } else if (param->dtmf == '#') {
1746 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1747 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1748 if (e_dtmf_last == '0') {
1752 /* processing keypad function */
1754 keypad_function(e_dtmf_last);
1760 /* set last time of dtmf */
1765 /* check for ## hookflash during dialing */
1767 if (e_action->index==ACTION_PASSWORD
1768 || e_action->index==ACTION_PASSWORD_WRITE)
1770 if (param->dtmf=='#') { /* current digit is '#' */
1771 if (e_state==EPOINT_STATE_IN_DISCONNECT
1772 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1786 /* dialing using dtmf digit */
1787 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1788 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1789 set_tone(portlist, "dialing");
1791 /* concat dialing string */
1792 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1793 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1794 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1800 /* port MESSAGE_CRYPT */
1801 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1803 /* send crypt response to cryptman */
1804 if (param->crypt.type == CR_MESSAGE_IND)
1805 cryptman_msg2man(param->crypt.data, param->crypt.len);
1807 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1810 /* port MESSAGE_OVERLAP */
1811 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1813 struct lcr_msg *message;
1815 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1817 /* signal to call tool */
1818 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1820 if (e_dialing_queue[0] && portlist) {
1821 /* send what we have not dialed yet, because we had no setup complete */
1822 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1823 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1824 SCPY(message->param.information.id, e_dialing_queue);
1825 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1826 message_put(message);
1827 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1828 e_dialing_queue[0] = '\0';
1830 /* check if pattern is available */
1831 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1832 /* indicate patterns */
1833 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1834 message_put(message);
1836 /* connect audio, if not already */
1837 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1838 message->param.audiopath = 1;
1839 message_put(message);
1841 /* indicate no patterns */
1842 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1843 message_put(message);
1845 /* disconnect audio, if not already */
1846 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1847 message->param.audiopath = 0;
1848 message_put(message);
1850 new_state(EPOINT_STATE_OUT_OVERLAP);
1851 /* if we are in a join */
1852 if (ea_endpoint->ep_join_id) {
1853 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1854 memcpy(&message->param, param, sizeof(union parameter));
1855 message_put(message);
1859 /* port MESSAGE_PROCEEDING */
1860 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1862 struct lcr_msg *message;
1864 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1866 /* signal to call tool */
1867 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1869 e_state = EPOINT_STATE_OUT_PROCEEDING;
1870 /* check if pattern is availatle */
1871 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1872 /* indicate patterns */
1873 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1874 message_put(message);
1876 /* connect audio, if not already */
1877 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1878 message->param.audiopath = 1;
1879 message_put(message);
1881 /* indicate no patterns */
1882 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1883 message_put(message);
1885 /* disconnect audio, if not already */
1886 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1887 message->param.audiopath = 0;
1888 message_put(message);
1890 /* if we are in a call */
1891 if (ea_endpoint->ep_join_id) {
1892 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1893 memcpy(&message->param, param, sizeof(union parameter));
1894 message_put(message);
1898 /* port MESSAGE_ALERTING */
1899 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1901 struct lcr_msg *message;
1903 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1905 /* signal to call tool */
1906 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1909 // set_tone(portlist, "hold");
1911 new_state(EPOINT_STATE_OUT_ALERTING);
1912 /* check if pattern is available */
1913 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1914 /* indicate patterns */
1915 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1916 message_put(message);
1918 /* connect audio, if not already */
1919 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1920 message->param.audiopath = 1;
1921 message_put(message);
1923 /* indicate no patterns */
1924 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1925 message_put(message);
1927 /* disconnect audio, if not already */
1928 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1929 message->param.audiopath = 0;
1930 message_put(message);
1932 /* if we are in a call */
1933 if (ea_endpoint->ep_join_id) {
1934 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1935 memcpy(&message->param, param, sizeof(union parameter));
1936 message_put(message);
1940 /* port MESSAGE_CONNECT */
1941 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1943 struct lcr_msg *message;
1945 unsigned int port_id = portlist->port_id;
1946 struct port_list *tportlist;
1948 struct interface *interface;
1951 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1953 /* signal to call tool */
1954 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1956 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1957 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1958 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1959 tportlist = ea_endpoint->ep_portlist;
1960 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1961 tportlist = tportlist->next;
1962 if (tportlist->port_id == port_id)
1963 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1964 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1965 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1966 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1967 message_put(message);
1968 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1969 ea_endpoint->free_portlist(tportlist);
1971 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1976 /* screen incoming connected id */
1977 interface = interface_first;
1979 if (!strcmp(e_connectinfo.interface, interface->name)) {
1982 interface = interface->next;
1985 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1987 /* screen connected name */
1989 SCPY(e_connectinfo.name, e_ext.name);
1991 /* add internal id to colp */
1992 SCPY(e_connectinfo.extension, e_ext.number);
1994 /* we store the connected port number */
1995 SCPY(e_extension_interface, e_connectinfo.interface);
1997 /* for internal and am calls, we get the extension's id */
1998 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1999 SCPY(e_connectinfo.id, e_ext.callerid);
2000 SCPY(e_connectinfo.extension, e_ext.number);
2001 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2002 e_connectinfo.ntype = e_ext.callerid_type;
2003 e_connectinfo.present = e_ext.callerid_present;
2005 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2006 e_connectinfo.itype = INFO_ITYPE_VBOX;
2007 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2010 new_state(EPOINT_STATE_CONNECT);
2012 /* set volume of rx and tx */
2013 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2014 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2015 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2016 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2017 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2018 message_put(message);
2021 unsched_timer(&e_cfnr_timeout);
2022 unsched_timer(&e_cfnr_call_timeout);
2023 if (e_ext.number[0])
2024 e_dtmf = 1; /* allow dtmf */
2027 /* other calls with no caller id (or not available for the extension) and force colp */
2028 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2029 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2030 if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT || portlist->port_type==PORT_TYPE_GSM_OUT) { /* external extension answered */
2031 port = find_port_id(portlist->port_id);
2033 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2034 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2039 /* send connect to join */
2040 if (ea_endpoint->ep_join_id) {
2041 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2042 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2043 message_put(message);
2045 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2046 message->param.audiopath = 1;
2047 message_put(message);
2048 } else if (!e_adminid) {
2050 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2051 SCPY(e_ext.number, e_cbcaller);
2052 new_state(EPOINT_STATE_IN_OVERLAP);
2053 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2055 /* get extension's info about terminal */
2056 if (!read_extension(&e_ext, e_ext.number)) {
2057 /* extension doesn't exist */
2058 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2059 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2060 new_state(EPOINT_STATE_OUT_DISCONNECT);
2061 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2065 /* put prefix in front of e_cbdialing */
2066 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2067 SCPY(e_dialinginfo.id, buffer);
2068 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2069 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2071 /* use caller id (or if exist: id_next_call) for this call */
2072 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2073 SCPY(e_callerinfo.extension, e_ext.number);
2074 if (e_ext.id_next_call_present >= 0) {
2075 SCPY(e_callerinfo.id, e_ext.id_next_call);
2076 e_callerinfo.present = e_ext.id_next_call_present;
2077 e_callerinfo.ntype = e_ext.id_next_call_type;
2078 e_ext.id_next_call_present = -1;
2079 /* extension is written */
2080 write_extension(&e_ext, e_ext.number);
2082 SCPY(e_callerinfo.id, e_ext.callerid);
2083 e_callerinfo.present = e_ext.callerid_present;
2084 e_callerinfo.ntype = e_ext.callerid_type;
2086 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2088 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2091 /* check if caller id is NOT authenticated */
2092 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2093 /* make call state to enter password */
2094 new_state(EPOINT_STATE_IN_OVERLAP);
2095 e_action = &action_password_write;
2096 unsched_timer(&e_match_timeout);
2097 e_match_to_action = NULL;
2098 e_dialinginfo.id[0] = '\0';
2099 e_extdialing = strchr(e_dialinginfo.id, '\0');
2100 schedule_timer(&e_password_timeout, 20, 0);
2103 /* incoming call (callback) */
2104 e_ruleset = ruleset_main;
2106 e_rule = e_ruleset->rule_first;
2108 e_extdialing = e_dialinginfo.id;
2109 if (e_dialinginfo.id[0]) {
2110 set_tone(portlist, "dialing");
2113 set_tone(portlist, "dialpbx");
2116 } else { /* testcall */
2117 set_tone(portlist, "hold");
2120 /* start recording if enabled, not when answering machine answers */
2121 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)) {
2122 /* check if we are a terminal */
2123 if (e_ext.number[0] == '\0')
2124 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2126 port = find_port_id(portlist->port_id);
2128 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2133 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2134 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2136 struct lcr_msg *message;
2138 unsigned int port_id = portlist->port_id;
2142 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2144 /* signal to call tool */
2145 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2147 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2148 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2149 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2154 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);
2155 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2156 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2158 /* check if we have more than one portlist relation and we just ignore the disconnect */
2159 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2160 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2161 portlist = ea_endpoint->ep_portlist;
2163 if (portlist->port_id == port_id)
2165 portlist = portlist->next;
2168 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2169 if (message_type != MESSAGE_RELEASE) {
2170 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2171 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2172 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2173 message_put(message);
2174 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2176 ea_endpoint->free_portlist(portlist);
2177 return; /* one relation removed */
2179 if (e_state == EPOINT_STATE_CONNECT) {
2180 /* use cause from port after connect */
2181 cause = param->disconnectinfo.cause;
2182 location = param->disconnectinfo.location;
2184 /* use multipoint cause if no connect yet */
2185 if (e_multipoint_cause) {
2186 cause = e_multipoint_cause;
2187 location = e_multipoint_location;
2189 cause = CAUSE_NOUSER;
2190 location = LOCATION_PRIVATE_LOCAL;
2194 unsched_timer(&e_cfnr_timeout);
2195 unsched_timer(&e_cfnr_call_timeout);
2197 /* process hangup */
2198 process_hangup(e_join_cause, e_join_location);
2199 e_multipoint_cause = 0;
2200 e_multipoint_location = 0;
2202 if (message_type == MESSAGE_DISCONNECT) {
2203 /* tone to disconnected end */
2204 SPRINT(buffer, "cause_%02x", cause);
2205 if (ea_endpoint->ep_portlist)
2206 set_tone(ea_endpoint->ep_portlist, buffer);
2208 new_state(EPOINT_STATE_IN_DISCONNECT);
2211 if (ea_endpoint->ep_join_id) {
2212 int haspatterns = 0;
2213 /* check if pattern is available */
2214 if (ea_endpoint->ep_portlist)
2215 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2216 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
2217 && message_type != MESSAGE_RELEASE) // if we release, we are done
2220 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2221 /* indicate patterns */
2222 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2223 message_put(message);
2224 /* connect audio, if not already */
2225 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2226 message->param.audiopath = 1;
2227 message_put(message);
2228 /* send disconnect */
2229 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2230 memcpy(&message->param, param, sizeof(union parameter));
2231 message_put(message);
2232 /* disable encryption if disconnected */
2233 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2235 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2238 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2241 if (message_type == MESSAGE_RELEASE)
2242 ea_endpoint->free_portlist(portlist);
2243 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2244 return; /* must exit here */
2247 /* port MESSAGE_TIMEOUT */
2248 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2252 trace_header("TIMEOUT", DIRECTION_IN);
2253 message_type = MESSAGE_DISCONNECT;
2254 switch (param->state) {
2255 case PORT_STATE_OUT_SETUP:
2256 case PORT_STATE_OUT_OVERLAP:
2257 add_trace("state", NULL, "outgoing setup/dialing");
2259 /* no user responding */
2260 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2261 return; /* must exit here */
2263 case PORT_STATE_IN_SETUP:
2264 case PORT_STATE_IN_OVERLAP:
2265 add_trace("state", NULL, "incoming setup/dialing");
2266 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2267 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2270 case PORT_STATE_OUT_PROCEEDING:
2271 add_trace("state", NULL, "outgoing proceeding");
2273 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2274 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2275 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2276 return; /* must exit here */
2278 case PORT_STATE_IN_PROCEEDING:
2279 add_trace("state", NULL, "incoming proceeding");
2280 param->disconnectinfo.cause = CAUSE_NOUSER;
2281 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2284 case PORT_STATE_OUT_ALERTING:
2285 add_trace("state", NULL, "outgoing alerting");
2287 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2288 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2289 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2290 return; /* must exit here */
2292 case PORT_STATE_CONNECT:
2293 add_trace("state", NULL, "connect");
2295 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2296 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2297 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2298 return; /* must exit here */
2300 case PORT_STATE_IN_ALERTING:
2301 add_trace("state", NULL, "incoming alerting");
2302 param->disconnectinfo.cause = CAUSE_NOANSWER;
2303 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2306 case PORT_STATE_IN_DISCONNECT:
2307 case PORT_STATE_OUT_DISCONNECT:
2308 add_trace("state", NULL, "disconnect");
2310 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2311 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2312 return; /* must exit here */
2315 param->disconnectinfo.cause = 31; /* normal unspecified */
2316 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2319 /* release call, disconnect isdn */
2321 new_state(EPOINT_STATE_OUT_DISCONNECT);
2322 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2323 SCPY(e_tone, cause);
2325 set_tone(portlist, cause);
2326 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2327 portlist = portlist->next;
2329 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2332 /* port MESSAGE_NOTIFY */
2333 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2335 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2337 struct lcr_msg *message;
2338 const char *logtext = "";
2341 /* signal to call tool */
2342 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);
2343 if (param->notifyinfo.notify) {
2344 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2347 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2348 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2349 case INFO_NOTIFY_REMOTE_HOLD:
2350 case INFO_NOTIFY_USER_SUSPENDED:
2351 /* tell call about it */
2352 if (ea_endpoint->ep_join_id) {
2353 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2354 message->param.audiopath = 0;
2355 message_put(message);
2359 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2360 case INFO_NOTIFY_USER_RESUMED:
2361 /* set volume of rx and tx */
2362 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2363 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2365 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2366 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2367 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2368 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2369 message_put(message);
2371 /* set current tone */
2373 set_tone(portlist, e_tone);
2374 /* tell call about it */
2375 if (ea_endpoint->ep_join_id) {
2376 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2377 message->param.audiopath = 1;
2378 message_put(message);
2383 /* get name of notify */
2384 switch(param->notifyinfo.notify) {
2389 logtext = "USER_SUSPENDED";
2392 logtext = "BEARER_SERVICE_CHANGED";
2395 logtext = "USER_RESUMED";
2398 logtext = "CONFERENCE_ESTABLISHED";
2401 logtext = "CONFERENCE_DISCONNECTED";
2404 logtext = "OTHER_PARTY_ADDED";
2407 logtext = "ISOLATED";
2410 logtext = "REATTACHED";
2413 logtext = "OTHER_PARTY_ISOLATED";
2416 logtext = "OTHER_PARTY_REATTACHED";
2419 logtext = "OTHER_PARTY_SPLIT";
2422 logtext = "OTHER_PARTY_DISCONNECTED";
2425 logtext = "CONFERENCE_FLOATING";
2428 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2431 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2434 logtext = "CALL_IS_A_WAITING_CALL";
2437 logtext = "DIVERSION_ACTIVATED";
2440 logtext = "RESERVED_CT_1";
2443 logtext = "RESERVED_CT_2";
2446 logtext = "REVERSE_CHARGING";
2449 logtext = "REMOTE_HOLD";
2452 logtext = "REMOTE_RETRIEVAL";
2455 logtext = "CALL_IS_DIVERTING";
2458 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2463 /* notify call if available */
2464 if (ea_endpoint->ep_join_id) {
2465 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2466 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2467 message_put(message);
2472 /* port MESSAGE_FACILITY */
2473 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2475 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2477 struct lcr_msg *message;
2479 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2480 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2481 message_put(message);
2484 /* port MESSAGE_SUSPEND */
2485 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2486 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2488 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2490 /* epoint is now parked */
2491 ea_endpoint->ep_park = 1;
2492 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2493 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2495 /* remove port relation */
2496 ea_endpoint->free_portlist(portlist);
2499 /* port MESSAGE_RESUME */
2500 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2501 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2503 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2505 /* epoint is now resumed */
2506 ea_endpoint->ep_park = 0;
2511 /* port sends message to the endpoint
2513 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2515 struct port_list *portlist;
2517 portlist = ea_endpoint->ep_portlist;
2519 if (port_id == portlist->port_id)
2521 portlist = portlist->next;
2524 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);
2528 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2529 switch(message_type) {
2530 case MESSAGE_DATA: /* data from port */
2531 /* check if there is a call */
2532 if (!ea_endpoint->ep_join_id)
2534 /* continue if only one portlist */
2535 if (ea_endpoint->ep_portlist->next != NULL)
2537 /* forward message */
2538 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2541 case MESSAGE_TONE_EOF: /* tone is end of file */
2542 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2544 if (e_action->index == ACTION_VBOX_PLAY) {
2547 if (e_action->index == ACTION_EFI) {
2553 case MESSAGE_TONE_COUNTER: /* counter info received */
2554 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);
2556 if (e_action->index == ACTION_VBOX_PLAY) {
2557 e_vbox_counter = param->counter.current;
2558 if (param->counter.max >= 0)
2559 e_vbox_counter_max = param->counter.max;
2563 /* PORT sends SETUP message */
2565 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);
2566 if (e_state!=EPOINT_STATE_IDLE) {
2567 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2570 port_setup(portlist, message_type, param);
2573 /* PORT sends INFORMATION message */
2574 case MESSAGE_INFORMATION: /* additional digits received */
2575 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);
2576 port_information(portlist, message_type, param);
2579 /* PORT sends FACILITY message */
2580 case MESSAGE_FACILITY:
2581 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2582 port_facility(portlist, message_type, param);
2585 /* PORT sends DTMF message */
2586 case MESSAGE_DTMF: /* dtmf digits received */
2587 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);
2588 port_dtmf(portlist, message_type, param);
2591 /* PORT sends CRYPT message */
2592 case MESSAGE_CRYPT: /* crypt response received */
2593 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2594 port_crypt(portlist, message_type, param);
2597 /* PORT sends MORE message */
2598 case MESSAGE_OVERLAP:
2599 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);
2600 if (e_state != EPOINT_STATE_OUT_SETUP) {
2601 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);
2604 port_overlap(portlist, message_type, param);
2607 /* PORT sends PROCEEDING message */
2608 case MESSAGE_PROCEEDING: /* port is proceeding */
2609 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);
2610 if (e_state!=EPOINT_STATE_OUT_SETUP
2611 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2612 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);
2615 port_proceeding(portlist, message_type, param);
2618 /* PORT sends ALERTING message */
2619 case MESSAGE_ALERTING:
2620 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);
2621 if (e_state!=EPOINT_STATE_OUT_SETUP
2622 && e_state!=EPOINT_STATE_OUT_OVERLAP
2623 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2624 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);
2627 port_alerting(portlist, message_type, param);
2630 /* PORT sends CONNECT message */
2631 case MESSAGE_CONNECT:
2632 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);
2633 if (e_state!=EPOINT_STATE_OUT_SETUP
2634 && e_state!=EPOINT_STATE_OUT_OVERLAP
2635 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2636 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2637 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2640 port_connect(portlist, message_type, param);
2643 /* PORT sends DISCONNECT message */
2644 case MESSAGE_DISCONNECT: /* port is disconnected */
2645 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);
2646 port_disconnect_release(portlist, message_type, param);
2649 /* PORT sends a RELEASE message */
2650 case MESSAGE_RELEASE: /* port releases */
2651 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);
2652 /* portlist is release at port_disconnect_release, thanx Paul */
2653 port_disconnect_release(portlist, message_type, param);
2656 /* PORT sends a TIMEOUT message */
2657 case MESSAGE_TIMEOUT:
2658 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);
2659 port_timeout(portlist, message_type, param);
2660 break; /* release */
2662 /* PORT sends a NOTIFY message */
2663 case MESSAGE_NOTIFY:
2664 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);
2665 port_notify(portlist, message_type, param);
2668 /* PORT sends a SUSPEND message */
2669 case MESSAGE_SUSPEND:
2670 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);
2671 port_suspend(portlist, message_type, param);
2672 break; /* suspend */
2674 /* PORT sends a RESUME message */
2675 case MESSAGE_RESUME:
2676 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);
2677 port_resume(portlist, message_type, param);
2681 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2682 /* port assigns bchannel */
2683 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2684 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);
2685 /* only one port is expected to be connected to bchannel */
2686 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2687 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2693 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);
2696 /* Note: this endpoint may be destroyed, so we MUST return */
2700 /* messages from join
2702 /* join MESSAGE_CRYPT */
2703 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2705 switch(param->crypt.type) {
2706 /* message from remote port to "crypt manager" */
2707 case CU_ACTK_REQ: /* activate key-exchange */
2708 case CU_ACTS_REQ: /* activate shared key */
2709 case CU_DACT_REQ: /* deactivate */
2710 case CU_INFO_REQ: /* request last info message */
2711 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2714 /* message from "crypt manager" to user */
2715 case CU_ACTK_CONF: /* key-echange done */
2716 case CU_ACTS_CONF: /* shared key done */
2717 case CU_DACT_CONF: /* deactivated */
2718 case CU_DACT_IND: /* deactivated */
2719 case CU_ERROR_IND: /* receive error message */
2720 case CU_INFO_IND: /* receive info message */
2721 case CU_INFO_CONF: /* receive info message */
2722 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2726 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);
2730 /* join MESSAGE_INFORMATION */
2731 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2733 struct lcr_msg *message;
2738 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2739 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2740 message_put(message);
2741 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2742 portlist = portlist->next;
2746 /* join MESSAGE_FACILITY */
2747 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2749 struct lcr_msg *message;
2751 if (!e_ext.facility && e_ext.number[0]) {
2756 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2757 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2758 message_put(message);
2759 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2760 portlist = portlist->next;
2764 /* join MESSAGE_MORE */
2765 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2767 struct lcr_msg *message;
2769 new_state(EPOINT_STATE_IN_OVERLAP);
2772 if (e_join_pattern && e_ext.own_setup) {
2773 /* disconnect audio */
2774 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2775 message->param.audiopath = 0;
2776 message_put(message);
2778 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2779 if (e_dialinginfo.id[0])
2780 set_tone(portlist, "dialing");
2782 set_tone(portlist, "dialtone");
2785 if (e_dialinginfo.id[0]) {
2786 set_tone(portlist, "dialing");
2788 if (e_ext.number[0])
2789 set_tone(portlist, "dialpbx");
2791 set_tone(portlist, "dialtone");
2795 /* join MESSAGE_PROCEEDING */
2796 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2798 struct lcr_msg *message;
2800 new_state(EPOINT_STATE_IN_PROCEEDING);
2802 /* own proceeding tone */
2803 if (e_join_pattern) {
2804 /* connect / disconnect audio */
2805 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2806 if (e_ext.own_proceeding)
2807 message->param.audiopath = 0;
2809 message->param.audiopath = 1;
2810 message_put(message);
2812 // UCPY(e_join_tone, "proceeding");
2814 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2815 message_put(message);
2816 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2818 set_tone(portlist, "proceeding");
2821 /* join MESSAGE_ALERTING */
2822 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2824 struct lcr_msg *message;
2826 new_state(EPOINT_STATE_IN_ALERTING);
2828 /* own alerting tone */
2829 if (e_join_pattern) {
2830 /* connect / disconnect audio */
2831 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2832 if (e_ext.own_alerting)
2833 message->param.audiopath = 0;
2835 message->param.audiopath = 1;
2836 message_put(message);
2839 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2840 message_put(message);
2841 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2843 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2844 set_tone(portlist, "ringing");
2847 if (e_ext.number[0])
2848 set_tone(portlist, "ringpbx");
2850 set_tone(portlist, "ringing");
2852 if (e_ext.number[0])
2853 e_dtmf = 1; /* allow dtmf */
2856 /* join MESSAGE_CONNECT */
2857 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2859 struct lcr_msg *message;
2862 new_state(EPOINT_STATE_CONNECT);
2863 // UCPY(e_join_tone, "");
2865 if (e_ext.number[0])
2866 e_dtmf = 1; /* allow dtmf */
2869 unsched_timer(&e_powerdial_timeout);
2870 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2872 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2873 memcpy(&message->param, param, sizeof(union parameter));
2875 /* screen clip if prefix is required */
2876 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2877 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2878 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2879 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2882 /* use internal caller id */
2883 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2884 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2885 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2888 /* handle restricted caller ids */
2889 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);
2890 /* display callerid if desired for extension */
2891 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));
2893 /* use conp, if enabld */
2894 // if (!e_ext.centrex)
2895 // message->param.connectinfo.name[0] = '\0';
2898 message_put(message);
2899 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2901 set_tone(portlist, NULL);
2903 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2904 message->param.audiopath = 1;
2905 message_put(message);
2910 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2911 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2914 struct lcr_msg *message;
2915 struct port_list *portlist = NULL;
2919 /* be sure that we are active */
2921 e_tx_state = NOTIFY_STATE_ACTIVE;
2923 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2924 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2925 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2927 /* set time for power dialing */
2928 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2931 /* set redial tone */
2932 if (ea_endpoint->ep_portlist) {
2935 set_tone(ea_endpoint->ep_portlist, "redial");
2936 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);
2937 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2938 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2939 new_state(EPOINT_STATE_IN_PROCEEDING);
2940 if (ea_endpoint->ep_portlist) {
2941 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2942 message_put(message);
2943 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2945 /* caused the error, that the first knock sound was not there */
2946 /* set_tone(portlist, "proceeding"); */
2948 /* send display of powerdialing */
2949 if (e_ext.display_dialing) {
2950 portlist = ea_endpoint->ep_portlist;
2952 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2954 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2956 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2957 message_put(message);
2958 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2959 portlist = portlist->next;
2969 if ((e_state!=EPOINT_STATE_CONNECT
2970 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2971 && e_state!=EPOINT_STATE_IN_OVERLAP
2972 && e_state!=EPOINT_STATE_IN_PROCEEDING
2973 && e_state!=EPOINT_STATE_IN_ALERTING)
2974 || !ea_endpoint->ep_portlist) { /* or no port */
2975 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2976 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2977 return; /* must exit here */
2980 if (!e_join_cause) {
2981 e_join_cause = param->disconnectinfo.cause;
2982 e_join_location = param->disconnectinfo.location;
2985 /* on release we need the audio again! */
2986 if (message_type == MESSAGE_RELEASE) {
2988 ea_endpoint->ep_join_id = 0;
2990 /* disconnect and select tone */
2991 new_state(EPOINT_STATE_OUT_DISCONNECT);
2992 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2993 /* if own_cause, we must release the join */
2994 if (e_ext.own_cause /* own cause */
2995 || !e_join_pattern) { /* no patterns */
2996 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);
2997 if (message_type != MESSAGE_RELEASE)
2998 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3000 } else { /* else we enable audio */
3001 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3002 message->param.audiopath = 1;
3003 message_put(message);
3005 /* send disconnect message */
3006 SCPY(e_tone, cause);
3007 portlist = ea_endpoint->ep_portlist;
3009 set_tone(portlist, cause);
3010 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3011 portlist = portlist->next;
3015 /* join MESSAGE_SETUP */
3016 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3018 struct lcr_msg *message;
3019 // struct interface *interface;
3021 /* if we already in setup state, we just update the dialing with new digits */
3022 if (e_state == EPOINT_STATE_OUT_SETUP
3023 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3024 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3025 /* if digits changed, what we have already dialed */
3026 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3027 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);
3028 /* release all ports */
3029 while((portlist = ea_endpoint->ep_portlist)) {
3030 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3031 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3032 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3033 message_put(message);
3034 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3035 ea_endpoint->free_portlist(portlist);
3038 /* disconnect audio */
3039 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3040 message->param.audiopath = 0;
3041 message_put(message);
3043 /* get dialing info */
3044 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3045 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3046 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3047 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3048 new_state(EPOINT_STATE_OUT_OVERLAP);
3051 schedule_timer(&e_redial_timeout, 1, 0);
3054 /* if we have a pending redial, so we just adjust the dialing number */
3055 if (e_redial_timeout.active) {
3056 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);
3057 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3060 if (!ea_endpoint->ep_portlist) {
3061 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3063 if (ea_endpoint->ep_portlist->next) {
3064 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3066 if (e_state == EPOINT_STATE_OUT_SETUP) {
3068 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);
3069 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3072 /* get what we have not dialed yet */
3073 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));
3074 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3075 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3076 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3077 message_put(message);
3078 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3080 /* always store what we have dialed or queued */
3081 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3085 if (e_state != EPOINT_STATE_IDLE) {
3086 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3089 /* if an internal extension is dialed, copy that number */
3090 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3091 SCPY(e_ext.number, param->setup.dialinginfo.id);
3092 /* if an internal extension is dialed, get extension's info about caller */
3093 if (e_ext.number[0]) {
3094 if (!read_extension(&e_ext, e_ext.number)) {
3095 e_ext.number[0] = '\0';
3096 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3100 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3101 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3102 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3103 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3105 /* process (voice over) data calls */
3106 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3107 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3108 memset(&e_capainfo, 0, sizeof(e_capainfo));
3109 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3110 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3111 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3114 new_state(EPOINT_STATE_OUT_SETUP);
3115 /* call special setup routine */
3119 /* join MESSAGE_mISDNSIGNAL */
3120 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3122 struct lcr_msg *message;
3125 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3126 memcpy(&message->param, param, sizeof(union parameter));
3127 message_put(message);
3128 portlist = portlist->next;
3132 /* join MESSAGE_NOTIFY */
3133 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3135 struct lcr_msg *message;
3138 if (param->notifyinfo.notify) {
3139 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3140 // /* if notification was generated locally, we turn hold music on/off */
3141 // if (param->notifyinfo.local)
3142 // 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)
3146 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3147 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3149 set_tone(portlist, "");
3150 portlist = portlist->next;
3153 portlist = ea_endpoint->ep_portlist;
3158 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3160 set_tone(portlist, "hold");
3161 portlist = portlist->next;
3163 portlist = ea_endpoint->ep_portlist;
3168 /* save new state */
3169 e_tx_state = new_state;
3172 /* notify port(s) about it */
3174 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3175 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3176 /* handle restricted caller ids */
3177 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3178 /* display callerid if desired for extension */
3179 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));
3180 message_put(message);
3181 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3182 portlist = portlist->next;
3186 /* JOIN sends messages to the endpoint
3188 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3190 struct port_list *portlist;
3191 struct lcr_msg *message;
3194 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3198 portlist = ea_endpoint->ep_portlist;
3200 /* send MESSAGE_DATA to port */
3201 if (message_type == MESSAGE_DATA) {
3202 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3203 /* skip if no port relation */
3206 /* skip if more than one port relation */
3209 /* forward audio data to port */
3210 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3215 // 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);
3216 switch(message_type) {
3217 /* JOIN SENDS TONE message */
3219 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);
3220 set_tone(portlist, param->tone.name);
3223 /* JOIN SENDS CRYPT message */
3225 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);
3226 join_crypt(portlist, message_type, param);
3229 /* JOIN sends INFORMATION message */
3230 case MESSAGE_INFORMATION:
3231 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);
3232 join_information(portlist, message_type, param);
3235 /* JOIN sends FACILITY message */
3236 case MESSAGE_FACILITY:
3237 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);
3238 join_facility(portlist, message_type, param);
3241 /* JOIN sends OVERLAP message */
3242 case MESSAGE_OVERLAP:
3243 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);
3244 if (e_state!=EPOINT_STATE_IN_SETUP
3245 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3246 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3249 join_overlap(portlist, message_type, param);
3252 /* JOIN sends PROCEEDING message */
3253 case MESSAGE_PROCEEDING:
3254 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);
3255 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3256 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3259 join_proceeding(portlist, message_type, param);
3262 /* JOIN sends ALERTING message */
3263 case MESSAGE_ALERTING:
3264 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);
3265 if (e_state!=EPOINT_STATE_IN_OVERLAP
3266 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3267 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3270 join_alerting(portlist, message_type, param);
3273 /* JOIN sends CONNECT message */
3274 case MESSAGE_CONNECT:
3275 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);
3276 if (e_state!=EPOINT_STATE_IN_OVERLAP
3277 && e_state!=EPOINT_STATE_IN_PROCEEDING
3278 && e_state!=EPOINT_STATE_IN_ALERTING) {
3279 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3282 join_connect(portlist, message_type, param);
3285 /* JOIN sends DISCONNECT/RELEASE message */
3286 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3287 case MESSAGE_RELEASE: /* JOIN releases */
3288 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);
3289 join_disconnect_release(message_type, param);
3292 /* JOIN sends SETUP message */
3294 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);
3295 join_setup(portlist, message_type, param);
3298 /* JOIN sends special mISDNSIGNAL message */
3299 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3300 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);
3301 join_mISDNsignal(portlist, message_type, param);
3305 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3306 /* JOIN requests bchannel */
3307 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3308 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel assignment %d from join.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type);
3309 /* only one port is expected to be connected to bchannel */
3316 set_tone(portlist, NULL);
3317 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3318 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3322 /* JOIN has pattern available */
3323 case MESSAGE_PATTERN: /* indicating pattern available */
3324 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);
3325 if (!e_join_pattern) {
3326 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3330 set_tone(portlist, NULL);
3331 portlist = portlist->next;
3333 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3334 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3335 message->param.audiopath = 1;
3336 message_put(message);
3340 /* JOIN has no pattern available */
3341 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3342 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);
3343 if (e_join_pattern) {
3344 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3346 /* disconnect our audio tx and rx */
3347 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3348 message->param.audiopath = 0;
3349 message_put(message);
3354 /* JOIN (dunno at the moment) */
3355 case MESSAGE_REMOTE_AUDIO:
3356 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);
3357 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3358 message->param.audiopath = param->channel;
3359 message_put(message);
3363 /* JOIN sends a notify message */
3364 case MESSAGE_NOTIFY:
3365 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);
3366 join_notify(portlist, message_type, param);
3369 /* JOIN wants keypad / dtmf */
3370 case MESSAGE_ENABLEKEYPAD:
3371 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);
3374 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3379 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);
3384 /* pick_join will connect the first incoming call found. the endpoint
3385 * will receivce a MESSAGE_CONNECT.
3387 int match_list(char *list, char *item)
3389 char *end, *next = NULL;
3391 /* no list make matching */
3396 /* eliminate white spaces */
3397 while (*list <= ' ')
3403 /* if end of list is reached, we return */
3404 if (list[0] == '\0')
3406 /* if we have more than one entry (left) */
3407 if ((end = strchr(list, ',')))
3410 next = end = strchr(list, '\0');
3411 while (*(end-1) <= ' ')
3413 /* if string part matches item */
3414 if (!strncmp(list, item, end-list))
3420 void EndpointAppPBX::pick_join(char *extensions)
3422 struct lcr_msg *message;
3423 struct port_list *portlist;
3425 class EndpointAppPBX *eapp, *found;
3427 class JoinPBX *joinpbx;
3428 struct join_relation *relation;
3431 /* find an endpoint that is ringing internally or vbox with higher priority */
3434 eapp = apppbx_first;
3436 if (eapp!=this && ea_endpoint->ep_portlist) {
3437 portlist = eapp->ea_endpoint->ep_portlist;
3439 if ((port = find_port_id(portlist->port_id))) {
3440 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3441 if (match_list(extensions, eapp->e_ext.number)) {
3447 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3448 && port->p_state==PORT_STATE_OUT_ALERTING)
3449 if (match_list(extensions, eapp->e_ext.number)) {
3453 portlist = portlist->next;
3461 /* if no endpoint found */
3463 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);
3465 set_tone(ea_endpoint->ep_portlist, "cause_10");
3466 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3467 new_state(EPOINT_STATE_OUT_DISCONNECT);
3472 if (ea_endpoint->ep_join_id) {
3473 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3476 if (!eapp->ea_endpoint->ep_join_id) {
3477 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3480 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3482 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3485 if (join->j_type != JOIN_TYPE_PBX) {
3486 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3489 joinpbx = (class JoinPBX *)join;
3490 relation = joinpbx->j_relation;
3492 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3495 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3496 relation = relation->next;
3498 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3503 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3505 if (options.deb & DEBUG_EPOINT) {
3506 class Join *debug_c = join_first;
3507 class Endpoint *debug_e = epoint_first;
3508 class Port *debug_p = port_first;
3510 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3512 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3514 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3515 debug_c = debug_c->next;
3517 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3519 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3520 debug_e = debug_e->next;
3522 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3524 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3525 debug_p = debug_p->next;
3530 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3531 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3532 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3534 /* connnecting our endpoint */
3535 new_state(EPOINT_STATE_CONNECT);
3536 if (e_ext.number[0])
3538 set_tone(ea_endpoint->ep_portlist, NULL);
3540 /* now we send a release to the ringing endpoint */
3541 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3542 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3543 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3544 message_put(message);
3546 /* we send a connect to the join with our caller id */
3547 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3548 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3549 message->param.connectinfo.present = e_callerinfo.present;
3550 message->param.connectinfo.screen = e_callerinfo.screen;
3551 message->param.connectinfo.itype = e_callerinfo.itype;
3552 message->param.connectinfo.ntype = e_callerinfo.ntype;
3553 message_put(message);
3555 /* we send a connect to our port with the remote callerid */
3556 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3557 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3558 message->param.connectinfo.present = eapp->e_callerinfo.present;
3559 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3560 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3561 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3562 /* handle restricted caller ids */
3563 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);
3564 /* display callerid if desired for extension */
3565 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));
3566 message_put(message);
3568 /* we send a connect to the audio path (not for vbox) */
3569 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3570 message->param.audiopath = 1;
3571 message_put(message);
3573 /* beeing paranoid, we make call update */
3574 trigger_work(&joinpbx->j_updatebridge);
3576 if (options.deb & DEBUG_EPOINT) {
3577 class Join *debug_c = join_first;
3578 class Endpoint *debug_e = epoint_first;
3579 class Port *debug_p = port_first;
3581 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3583 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3585 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3586 debug_c = debug_c->next;
3588 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3590 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3591 debug_e = debug_e->next;
3593 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3595 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3596 debug_p = debug_p->next;
3602 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3604 void EndpointAppPBX::join_join(void)
3606 struct lcr_msg *message;
3607 struct join_relation *our_relation, *other_relation;
3608 struct join_relation **our_relation_pointer, **other_relation_pointer;
3609 class Join *our_join, *other_join;
3610 class JoinPBX *our_joinpbx, *other_joinpbx;
3611 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3612 class Port *our_port, *other_port;
3613 class Pdss1 *our_pdss1, *other_pdss1;
3615 /* are we a candidate to join a join? */
3616 our_join = find_join_id(ea_endpoint->ep_join_id);
3618 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3621 if (our_join->j_type != JOIN_TYPE_PBX) {
3622 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3625 our_joinpbx = (class JoinPBX *)our_join;
3626 if (!ea_endpoint->ep_portlist) {
3627 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3630 if (!e_ext.number[0]) {
3631 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3634 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3636 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3639 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3640 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3643 our_pdss1 = (class Pdss1 *)our_port;
3645 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3646 other_eapp = apppbx_first;
3648 if (other_eapp == this) {
3649 other_eapp = other_eapp->next;
3652 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);
3653 if (other_eapp->e_ext.number[0] /* has terminal */
3654 && other_eapp->ea_endpoint->ep_portlist /* has port */
3655 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3656 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3657 if (other_port) { /* port still exists */
3658 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3659 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3660 other_pdss1 = (class Pdss1 *)other_port;
3661 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);
3662 if (other_pdss1->p_m_hold /* port is on hold */
3663 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3664 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3667 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3670 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3673 other_eapp = other_eapp->next;
3676 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3679 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3681 /* if we have the same join */
3682 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3683 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3686 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3688 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3691 if (other_join->j_type != JOIN_TYPE_PBX) {
3692 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3695 other_joinpbx = (class JoinPBX *)other_join;
3696 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3697 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3701 /* remove relation to endpoint for join on hold */
3702 other_relation = other_joinpbx->j_relation;
3703 other_relation_pointer = &other_joinpbx->j_relation;
3704 while(other_relation) {
3705 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3706 /* detach other endpoint on hold */
3707 *other_relation_pointer = other_relation->next;
3708 FREE(other_relation, sizeof(struct join_relation));
3710 other_relation = *other_relation_pointer;
3711 other_eapp->ea_endpoint->ep_join_id = 0;
3715 /* change join/hold pointer of endpoint to the new join */
3716 temp_epoint = find_epoint_id(other_relation->epoint_id);
3718 if (temp_epoint->ep_join_id == other_join->j_serial)
3719 temp_epoint->ep_join_id = our_join->j_serial;
3722 other_relation_pointer = &other_relation->next;
3723 other_relation = other_relation->next;
3725 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3727 /* join call relations */
3728 our_relation = our_joinpbx->j_relation;
3729 our_relation_pointer = &our_joinpbx->j_relation;
3730 while(our_relation) {
3731 our_relation_pointer = &our_relation->next;
3732 our_relation = our_relation->next;
3734 *our_relation_pointer = other_joinpbx->j_relation;
3735 other_joinpbx->j_relation = NULL;
3736 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3738 /* release endpoint on hold */
3739 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3740 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3741 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3742 message_put(message);
3744 /* if we are not a partyline, we get partyline state from other join */
3745 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3747 /* remove empty join */
3749 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3751 /* mixer must update */
3752 trigger_work(&our_joinpbx->j_updatebridge);
3754 /* we send a retrieve to that endpoint */
3755 // mixer will update the hold-state of the join and send it to the endpoints is changes
3759 /* check if we have an external call
3760 * this is used to check for encryption ability
3762 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3764 struct join_relation *relation;
3766 class JoinPBX *joinpbx;
3767 class Endpoint *epoint;
3769 /* some paranoia check */
3770 if (!ea_endpoint->ep_portlist) {
3771 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3772 *errstr = "No Call";
3775 if (!e_ext.number[0]) {
3776 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3777 *errstr = "No Call";
3781 /* check if we have a join with 2 parties */
3782 join = find_join_id(ea_endpoint->ep_join_id);
3784 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3785 *errstr = "No Call";
3788 if (join->j_type != JOIN_TYPE_PBX) {
3789 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3790 *errstr = "No PBX Call";
3793 joinpbx = (class JoinPBX *)join;
3794 relation = joinpbx->j_relation;
3796 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3797 *errstr = "No Call";
3800 if (!relation->next) {
3801 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3802 *errstr = "No Call";
3805 if (relation->next->next) {
3806 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3807 *errstr = "Err: Conference";
3810 if (relation->epoint_id == ea_endpoint->ep_serial) {
3811 relation = relation->next;
3812 if (relation->epoint_id == ea_endpoint->ep_serial) {
3813 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3814 *errstr = "Software Error";
3819 /* check remote port for external call */
3820 epoint = find_epoint_id(relation->epoint_id);
3822 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3823 *errstr = "No Call";
3826 if (!epoint->ep_portlist) {
3827 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3828 *errstr = "No Call";
3831 *port = find_port_id(epoint->ep_portlist->port_id);
3833 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3834 *errstr = "No Call";
3837 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3838 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3839 *errstr = "No Ext Call";
3842 if ((*port)->p_state != PORT_STATE_CONNECT) {
3843 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3844 *errstr = "No Ext Connect";
3850 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3852 const char *logtext = "unknown";
3855 switch(message_type) {
3857 trace_header("SETUP", dir);
3858 if (dir == DIRECTION_OUT)
3859 add_trace("to", NULL, "CH(%lu)", port_id);
3860 if (dir == DIRECTION_IN)
3861 add_trace("from", NULL, "CH(%lu)", port_id);
3862 if (param->setup.callerinfo.extension[0])
3863 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3864 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3865 switch(param->setup.callerinfo.present) {
3866 case INFO_PRESENT_RESTRICTED:
3867 add_trace("caller id", "present", "restricted");
3869 case INFO_PRESENT_ALLOWED:
3870 add_trace("caller id", "present", "allowed");
3873 add_trace("caller id", "present", "not available");
3875 if (param->setup.callerinfo.ntype2) {
3876 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3877 switch(param->setup.callerinfo.present) {
3878 case INFO_PRESENT_RESTRICTED:
3879 add_trace("caller id2", "present", "restricted");
3881 case INFO_PRESENT_ALLOWED:
3882 add_trace("caller id2", "present", "allowed");
3885 add_trace("caller id2", "present", "not available");
3888 if (param->setup.redirinfo.id[0]) {
3889 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3890 switch(param->setup.redirinfo.present) {
3891 case INFO_PRESENT_RESTRICTED:
3892 add_trace("redir'ing", "present", "restricted");
3894 case INFO_PRESENT_ALLOWED:
3895 add_trace("redir'ing", "present", "allowed");
3898 add_trace("redir'ing", "present", "not available");
3901 if (param->setup.dialinginfo.id[0])
3902 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3903 if (param->setup.dialinginfo.keypad[0])
3904 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3905 if (param->setup.dialinginfo.display[0])
3906 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3907 if (param->setup.dialinginfo.sending_complete)
3908 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3912 case MESSAGE_OVERLAP:
3913 trace_header("SETUP ACKNOWLEDGE", dir);
3914 if (dir == DIRECTION_OUT)
3915 add_trace("to", NULL, "CH(%lu)", port_id);
3916 if (dir == DIRECTION_IN)
3917 add_trace("from", NULL, "CH(%lu)", port_id);
3921 case MESSAGE_PROCEEDING:
3922 trace_header("PROCEEDING", dir);
3923 if (dir == DIRECTION_OUT)
3924 add_trace("to", NULL, "CH(%lu)", port_id);
3925 if (dir == DIRECTION_IN)
3926 add_trace("from", NULL, "CH(%lu)", port_id);
3930 case MESSAGE_ALERTING:
3931 trace_header("ALERTING", dir);
3932 if (dir == DIRECTION_OUT)
3933 add_trace("to", NULL, "CH(%lu)", port_id);
3934 if (dir == DIRECTION_IN)
3935 add_trace("from", NULL, "CH(%lu)", port_id);
3939 case MESSAGE_CONNECT:
3940 trace_header("CONNECT", dir);
3941 if (dir == DIRECTION_OUT)
3942 add_trace("to", NULL, "CH(%lu)", port_id);
3943 if (dir == DIRECTION_IN)
3944 add_trace("from", NULL, "CH(%lu)", port_id);
3945 if (param->connectinfo.extension[0])
3946 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3947 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3948 switch(param->connectinfo.present) {
3949 case INFO_PRESENT_RESTRICTED:
3950 add_trace("connect id", "present", "restricted");
3952 case INFO_PRESENT_ALLOWED:
3953 add_trace("connect id", "present", "allowed");
3956 add_trace("connect id", "present", "not available");
3958 if (param->connectinfo.display[0])
3959 add_trace("display", NULL, "%s", param->connectinfo.display);
3963 case MESSAGE_DISCONNECT:
3964 case MESSAGE_RELEASE:
3965 if (message_type == MESSAGE_DISCONNECT)
3966 trace_header("DISCONNECT", dir);
3968 trace_header("RELEASE", dir);
3969 if (dir == DIRECTION_OUT)
3970 add_trace("to", NULL, "CH(%lu)", port_id);
3971 if (dir == DIRECTION_IN)
3972 add_trace("from", NULL, "CH(%lu)", port_id);
3973 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3974 switch(param->disconnectinfo.location) {
3976 add_trace("cause", "location", "0-User");
3978 case LOCATION_PRIVATE_LOCAL:
3979 add_trace("cause", "location", "1-Local-PBX");
3981 case LOCATION_PUBLIC_LOCAL:
3982 add_trace("cause", "location", "2-Local-Exchange");
3984 case LOCATION_TRANSIT:
3985 add_trace("cause", "location", "3-Transit");
3987 case LOCATION_PUBLIC_REMOTE:
3988 add_trace("cause", "location", "4-Remote-Exchange");
3990 case LOCATION_PRIVATE_REMOTE:
3991 add_trace("cause", "location", "5-Remote-PBX");
3993 case LOCATION_INTERNATIONAL:
3994 add_trace("cause", "location", "7-International-Exchange");
3996 case LOCATION_BEYOND:
3997 add_trace("cause", "location", "10-Beyond-Interworking");
4000 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4002 if (param->disconnectinfo.display[0])
4003 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4007 case MESSAGE_NOTIFY:
4008 switch(param->notifyinfo.notify) {
4013 logtext = "USER_SUSPENDED";
4016 logtext = "BEARER_SERVICE_CHANGED";
4019 logtext = "USER_RESUMED";
4022 logtext = "CONFERENCE_ESTABLISHED";
4025 logtext = "CONFERENCE_DISCONNECTED";
4028 logtext = "OTHER_PARTY_ADDED";
4031 logtext = "ISOLATED";
4034 logtext = "REATTACHED";
4037 logtext = "OTHER_PARTY_ISOLATED";
4040 logtext = "OTHER_PARTY_REATTACHED";
4043 logtext = "OTHER_PARTY_SPLIT";
4046 logtext = "OTHER_PARTY_DISCONNECTED";
4049 logtext = "CONFERENCE_FLOATING";
4052 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4055 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4058 logtext = "CALL_IS_A_WAITING_CALL";
4061 logtext = "DIVERSION_ACTIVATED";
4064 logtext = "RESERVED_CT_1";
4067 logtext = "RESERVED_CT_2";
4070 logtext = "REVERSE_CHARGING";
4073 logtext = "REMOTE_HOLD";
4076 logtext = "REMOTE_RETRIEVAL";
4079 logtext = "CALL_IS_DIVERTING";
4082 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4086 trace_header("NOTIFY", dir);
4087 if (dir == DIRECTION_OUT)
4088 add_trace("to", NULL, "CH(%lu)", port_id);
4089 if (dir == DIRECTION_IN)
4090 add_trace("from", NULL, "CH(%lu)", port_id);
4091 if (param->notifyinfo.notify)
4092 add_trace("indicator", NULL, "%s", logtext);
4093 if (param->notifyinfo.id[0]) {
4094 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4095 switch(param->notifyinfo.present) {
4096 case INFO_PRESENT_RESTRICTED:
4097 add_trace("redir'on", "present", "restricted");
4099 case INFO_PRESENT_ALLOWED:
4100 add_trace("redir'on", "present", "allowed");
4103 add_trace("redir'on", "present", "not available");
4106 if (param->notifyinfo.display[0])
4107 add_trace("display", NULL, "%s", param->notifyinfo.display);
4111 case MESSAGE_INFORMATION:
4112 trace_header("INFORMATION", dir);
4113 if (dir == DIRECTION_OUT)
4114 add_trace("to", NULL, "CH(%lu)", port_id);
4115 if (dir == DIRECTION_IN)
4116 add_trace("from", NULL, "CH(%lu)", port_id);
4117 if (param->information.id[0])
4118 add_trace("dialing", NULL, "%s", param->information.id);
4119 if (param->information.display[0])
4120 add_trace("display", NULL, "%s", param->information.display);
4121 if (param->information.sending_complete)
4122 add_trace("complete", NULL, "true", param->information.sending_complete);
4126 case MESSAGE_FACILITY:
4127 trace_header("FACILITY", dir);
4128 if (dir == DIRECTION_OUT)
4129 add_trace("to", NULL, "CH(%lu)", port_id);
4130 if (dir == DIRECTION_IN)
4131 add_trace("from", NULL, "CH(%lu)", port_id);
4136 trace_header("TONE", dir);
4137 if (dir == DIRECTION_OUT)
4138 add_trace("to", NULL, "CH(%lu)", port_id);
4139 if (dir == DIRECTION_IN)
4140 add_trace("from", NULL, "CH(%lu)", port_id);
4141 if (param->tone.name[0]) {
4142 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4143 add_trace("name", NULL, "%s", param->tone.name);
4145 add_trace("off", NULL, NULL);
4149 case MESSAGE_SUSPEND:
4150 case MESSAGE_RESUME:
4151 if (message_type == MESSAGE_SUSPEND)
4152 trace_header("SUSPEND", dir);
4154 trace_header("RESUME", dir);
4155 if (dir == DIRECTION_OUT)
4156 add_trace("to", NULL, "CH(%lu)", port_id);
4157 if (dir == DIRECTION_IN)
4158 add_trace("from", NULL, "CH(%lu)", port_id);
4159 if (param->parkinfo.len)
4160 add_trace("length", NULL, "%d", param->parkinfo.len);
4165 case MESSAGE_BCHANNEL:
4166 trace_header("BCHANNEL", dir);
4167 switch(param->bchannel.type) {
4168 case BCHANNEL_REQUEST:
4169 add_trace("type", NULL, "request");
4171 case BCHANNEL_ASSIGN:
4172 add_trace("type", NULL, "assign");
4174 case BCHANNEL_ASSIGN_ACK:
4175 add_trace("type", NULL, "assign_ack");
4177 case BCHANNEL_REMOVE:
4178 add_trace("type", NULL, "remove");
4180 case BCHANNEL_REMOVE_ACK:
4181 add_trace("type", NULL, "remove_ack");
4184 if (param->bchannel.addr)
4185 add_trace("address", NULL, "%x", param->bchannel.addr);
4191 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4195 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4197 struct lcr_msg *message;
4201 if (!portlist->port_id)
4204 if (!e_connectedmode) {
4205 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4206 message->param.disconnectinfo.cause = cause;
4207 message->param.disconnectinfo.location = location;
4209 SCPY(message->param.disconnectinfo.display, display);
4211 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4213 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4215 SCPY(message->param.notifyinfo.display, display);
4217 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4219 message_put(message);
4220 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);