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 'external' 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 */
900 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
901 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
906 /* string from unconditional call forward (cfu) */
909 /* present to forwarded party */
910 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
911 e_callerinfo.present = INFO_PRESENT_ALLOWED;
913 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
917 /* string from busy call forward (cfb) */
920 class EndpointAppPBX *checkapp = apppbx_first;
922 if (checkapp != this) { /* any other endpoint except our own */
923 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
924 /* present to forwarded party */
925 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
926 e_callerinfo.present = INFO_PRESENT_ALLOWED;
928 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
932 checkapp = checkapp->next;
936 /* string from no-response call forward (cfnr) */
939 /* when cfnr is done, out_setup() will setup the call */
940 if (e_cfnr_call_timeout.active) {
941 /* present to forwarded party */
942 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
943 e_callerinfo.present = INFO_PRESENT_ALLOWED;
947 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
948 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
949 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
950 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);
954 /* call to all internal interfaces */
955 p = e_ext.interfaces;
956 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
959 while(*p!=',' && *p!='\0')
964 /* found interface */
965 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
966 /* hunt for mISDNport and create Port */
967 mISDNport = hunt_port(ifname, &channel);
969 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
970 add_trace("interface", NULL, "%s", ifname);
974 /* creating INTERNAL port */
975 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
978 port = ss5_hunt_line(mISDNport);
982 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);
985 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
990 FATAL("No memory for Port instance\n");
991 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
992 memset(&dialinginfo, 0, sizeof(dialinginfo));
993 SCPY(dialinginfo.id, e_dialinginfo.id);
994 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
995 dialinginfo.ntype = e_dialinginfo.ntype;
996 /* create port_list relation */
997 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
999 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1001 goto check_anycall_intern;
1003 /* directory.list */
1004 if (e_callerinfo.id[0] && e_ext.display_name) {
1005 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1007 SCPY(e_callerinfo.name, dirname);
1009 // dss1 = (class Pdss1 *)port;
1011 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1012 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1013 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1014 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1015 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1016 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1017 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1018 //terminal if (e_dialinginfo.id)
1019 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1020 /* handle restricted caller ids */
1021 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);
1022 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);
1023 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);
1024 /* display callerid if desired for extension */
1025 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));
1026 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1027 /* use cnip, if enabld */
1028 // if (!e_ext.centrex)
1029 // message->param.setup.callerinfo.name[0] = '\0';
1030 /* screen clip if prefix is required */
1031 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1032 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1033 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1034 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1036 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1037 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1038 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1039 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1041 /* use internal caller id */
1042 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1043 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1044 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1045 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1047 message_put(message);
1048 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1052 /* string from parallel call forward (cfp) */
1055 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1056 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1057 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1061 vbox_only: /* entry point for answering machine only */
1062 cfu_only: /* entry point for cfu */
1063 cfb_only: /* entry point for cfb */
1064 cfnr_only: /* entry point for cfnr */
1065 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1069 /* only if vbox should be dialed, and terminal is given */
1070 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1071 /* go to the end of p */
1074 /* answering vbox call */
1075 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1077 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1078 FATAL("No memory for VBOX Port instance\n");
1079 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1080 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1083 while(*p!=',' && *p!='\0')
1088 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1089 /* hunt for mISDNport and create Port */
1090 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1092 /* creating EXTERNAL port*/
1093 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1096 port = ss5_hunt_line(mISDNport);
1099 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);
1101 FATAL("No memory for Port instance\n");
1102 earlyb = mISDNport->earlyb;
1105 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1106 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1111 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1112 goto check_anycall_intern;
1114 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1115 memset(&dialinginfo, 0, sizeof(dialinginfo));
1116 SCPY(dialinginfo.id, cfp);
1117 dialinginfo.itype = INFO_ITYPE_ISDN;
1118 dialinginfo.ntype = e_dialinginfo.ntype;
1119 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1121 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1123 goto check_anycall_intern;
1125 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1126 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1127 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1128 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1129 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1130 /* if clip is hidden */
1131 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1132 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1133 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1134 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1135 message->param.setup.callerinfo.present = e_ext.callerid_present;
1136 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1138 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1139 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1140 //terminal if (e_dialinginfo.id)
1141 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1142 /* handle restricted caller ids */
1143 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);
1144 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);
1145 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);
1146 /* display callerid if desired for extension */
1147 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));
1148 message_put(message);
1149 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1153 check_anycall_intern:
1154 /* now we have all ports created */
1156 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1158 if (!ea_endpoint->ep_join_id)
1160 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1161 return; /* must exit here */
1165 /* *********************** external call */
1167 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1168 /* call to extenal interfaces */
1169 if (e_dialinginfo.keypad[0])
1170 p = e_dialinginfo.keypad;
1172 p = e_dialinginfo.id;
1175 while(*p!=',' && *p!='\0')
1176 SCCAT(number, *p++);
1180 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");
1181 /* hunt for mISDNport and create Port */
1182 /* hunt for mISDNport and create Port */
1183 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1185 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1186 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1188 goto check_anycall_extern;
1190 /* creating EXTERNAL port*/
1191 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1194 port = ss5_hunt_line(mISDNport);
1197 if (!mISDNport->gsm)
1198 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);
1201 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1206 FATAL("No memory for Port instance\n");
1207 earlyb = mISDNport->earlyb;
1208 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1209 memset(&dialinginfo, 0, sizeof(dialinginfo));
1210 if (e_dialinginfo.keypad[0])
1211 SCPY(dialinginfo.keypad, number);
1213 SCPY(dialinginfo.id, number);
1214 dialinginfo.itype = INFO_ITYPE_ISDN;
1215 dialinginfo.ntype = e_dialinginfo.ntype;
1216 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1218 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1220 goto check_anycall_extern;
1222 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1223 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1224 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1225 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1226 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1227 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1228 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1229 //terminal if (e_dialinginfo.id)
1230 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1231 /* handle restricted caller ids */
1232 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);
1233 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);
1234 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);
1235 /* display callerid if desired for extension */
1236 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));
1237 message_put(message);
1238 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1242 check_anycall_extern:
1243 /* now we have all ports created */
1245 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1247 if (!ea_endpoint->ep_join_id)
1249 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1250 return; /* must exit here */
1257 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1259 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1261 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1264 unsched_timer(&ea->e_redial_timeout);
1265 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1266 ea->e_multipoint_cause = 0;
1267 ea->e_multipoint_location = 0;
1268 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1269 ea->e_join_pattern = 0;
1270 ea->process_dialing(1);
1271 /* we must exit, because our endpoint might be gone */
1276 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1278 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1280 if (!ea->e_action) {
1281 unsched_timer(&ea->e_redial_timeout);
1282 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1283 ea->process_dialing(0);
1284 /* we must exit, because our endpoint might be gone */
1290 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1292 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1294 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1296 ea->new_state(EPOINT_STATE_OUT_SETUP);
1297 /* call special setup routine */
1303 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1305 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1307 /* leave power dialing on */
1308 ea->e_powerdial_on = 1;
1309 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1312 ea->e_ruleset = ruleset_main;
1314 ea->e_rule = ea->e_ruleset->rule_first;
1315 ea->e_action = NULL;
1316 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1317 ea->process_dialing(0);
1322 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1324 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1325 struct port_list *portlist;
1326 struct lcr_msg *message;
1328 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1330 /* release all ports */
1331 while((portlist = ea->ea_endpoint->ep_portlist)) {
1332 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1333 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1334 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1335 message_put(message);
1336 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1337 ea->ea_endpoint->free_portlist(portlist);
1340 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1341 message->param.audiopath = 0;
1342 message_put(message);
1343 /* indicate no patterns */
1344 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1345 message_put(message);
1346 /* set setup state, since we have no response from the new join */
1347 ea->new_state(EPOINT_STATE_OUT_SETUP);
1352 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1354 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1356 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);
1362 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1364 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1366 if (ea->e_state == EPOINT_STATE_IDLE) {
1367 /* epoint is idle, check callback */
1368 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1369 ea->new_state(EPOINT_STATE_OUT_SETUP);
1376 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1378 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1380 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1381 struct port_list *portlist;
1383 ea->e_ruleset = ruleset_main;
1385 ea->e_rule = ea->e_ruleset->rule_first;
1386 ea->e_action = NULL;
1387 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1388 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1390 ea->e_connectedmode = 0;
1392 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1393 portlist = ea->ea_endpoint->ep_portlist;
1395 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1396 ea->set_tone(portlist, "cause_10");
1403 /* doing a hookflash */
1404 void EndpointAppPBX::hookflash(void)
1409 /* be sure that we are active */
1411 e_tx_state = NOTIFY_STATE_ACTIVE;
1413 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1415 if (ea_endpoint->ep_use > 1) {
1416 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1419 /* dialtone after pressing the hash key */
1420 process_hangup(e_join_cause, e_join_location);
1421 e_multipoint_cause = 0;
1422 e_multipoint_location = 0;
1423 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1425 port->set_echotest(0);
1427 if (ea_endpoint->ep_join_id) {
1428 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1430 e_ruleset = ruleset_main;
1432 e_rule = e_ruleset->rule_first;
1434 new_state(EPOINT_STATE_IN_OVERLAP);
1435 e_connectedmode = 1;
1436 SCPY(e_dialinginfo.id, e_ext.prefix);
1437 e_extdialing = e_dialinginfo.id;
1439 if (e_dialinginfo.id[0]) {
1440 set_tone(ea_endpoint->ep_portlist, "dialing");
1443 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1451 /* messages from port
1453 /* port MESSAGE_SETUP */
1454 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1456 struct lcr_msg *message;
1458 int writeext; /* flags need to write extension after modification */
1460 struct interface *interface;
1462 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1464 portlist->port_type = param->setup.port_type;
1465 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1466 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1467 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1468 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1470 /* convert (inter-)national number type */
1471 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1472 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1474 // e_dtmf = param->setup.dtmf;
1475 /* screen incoming caller id */
1476 interface = interface_first;
1478 if (!strcmp(e_callerinfo.interface, interface->name)) {
1481 interface = interface->next;
1484 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1485 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1488 /* process extension */
1489 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1490 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1491 /* port makes call from extension */
1492 SCPY(e_callerinfo.extension, e_callerinfo.id);
1493 SCPY(e_ext.number, e_callerinfo.extension);
1494 SCPY(e_extension_interface, e_callerinfo.interface);
1496 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1499 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1500 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1502 /* get extension's info about caller */
1503 if (!read_extension(&e_ext, e_ext.number)) {
1504 /* extension doesn't exist */
1505 trace_header("EXTENSION (not created)", DIRECTION_IN);
1506 add_trace("extension", NULL, "%s", e_ext.number);
1508 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1509 new_state(EPOINT_STATE_OUT_DISCONNECT);
1510 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1511 e_ext.number[0] = '\0'; /* no terminal */
1516 /* put prefix (next) in front of e_dialinginfo.id */
1517 if (e_ext.next[0]) {
1518 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1519 SCPY(e_dialinginfo.id, buffer);
1520 e_ext.next[0] = '\0';
1522 } else if (e_ext.prefix[0]) {
1523 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1524 SCPY(e_dialinginfo.id, buffer);
1527 /* screen caller id by extension's config */
1528 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1530 SCPY(e_callerinfo.name, e_ext.name);
1531 /* use caller id (or if exist: id_next_call) for this call */
1532 if (e_ext.id_next_call_present >= 0) {
1533 SCPY(e_callerinfo.id, e_ext.id_next_call);
1534 /* if we restrict the pesentation */
1535 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1536 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1537 else e_callerinfo.present = e_ext.id_next_call_present;
1538 e_callerinfo.ntype = e_ext.id_next_call_type;
1539 e_ext.id_next_call_present = -1;
1542 SCPY(e_callerinfo.id, e_ext.callerid);
1543 /* if we restrict the pesentation */
1544 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1545 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1546 else e_callerinfo.present = e_ext.callerid_present;
1547 e_callerinfo.ntype = e_ext.callerid_type;
1549 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1551 /* extension is written */
1553 write_extension(&e_ext, e_ext.number);
1555 /* set volume of rx and tx */
1556 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1557 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1558 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1559 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1560 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1561 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1562 message_put(message);
1565 /* start recording if enabled */
1566 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1567 /* check if we are a terminal */
1568 if (e_ext.number[0] == '\0')
1569 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1571 port = find_port_id(portlist->port_id);
1573 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1577 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1578 /* no terminal identification */
1579 e_ext.number[0] = '\0';
1580 e_extension_interface[0] = '\0';
1581 memset(&e_ext, 0, sizeof(e_ext));
1582 e_ext.rights = 4; /* right to dial internat */
1586 e_ruleset = ruleset_main;
1588 e_rule = e_ruleset->rule_first;
1590 e_extdialing = e_dialinginfo.id;
1591 new_state(EPOINT_STATE_IN_SETUP);
1592 if (e_dialinginfo.id[0]) {
1593 set_tone(portlist, "dialing");
1595 if (e_ext.number[0])
1596 set_tone(portlist, "dialpbx");
1598 set_tone(portlist, "dialtone");
1601 if (e_state == EPOINT_STATE_IN_SETUP) {
1602 /* request MORE info, if not already at higher state */
1603 new_state(EPOINT_STATE_IN_OVERLAP);
1604 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1605 message_put(message);
1606 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1610 /* port MESSAGE_INFORMATION */
1611 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1613 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1615 /* ignore information message without digit information */
1616 if (!param->information.id[0])
1621 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1623 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1628 /* if vbox_play is done, the information are just used as they come */
1630 if (e_action->index == ACTION_VBOX_PLAY) {
1631 /* concat dialing string */
1632 SCAT(e_dialinginfo.id, param->information.id);
1637 /* keypad when disconnect but in connected mode */
1638 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1639 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1640 /* processing keypad function */
1641 if (param->information.id[0] == '0') {
1647 /* keypad when connected */
1648 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1649 if (e_ext.keypad || e_enablekeypad) {
1650 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1651 /* processing keypad function */
1652 if (param->information.id[0] == '0') {
1655 if (param->information.id[0])
1656 keypad_function(param->information.id[0]);
1658 if (e_ext.number[0])
1659 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1661 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1666 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1667 if (e_ext.number[0])
1668 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1670 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1674 if (!param->information.id[0])
1676 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1677 set_tone(portlist, "dialing");
1680 if (e_action->index==ACTION_OUTDIAL
1681 || e_action->index==ACTION_EXTERNAL
1682 || e_action->index==ACTION_REMOTE) {
1684 set_tone(portlist, "dialing");
1685 else if (!e_extdialing[0])
1686 set_tone(portlist, "dialing");
1688 /* concat dialing string */
1689 SCAT(e_dialinginfo.id, param->information.id);
1693 /* port MESSAGE_DTMF */
1694 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1700 /* only if dtmf detection is enabled */
1702 trace_header("DTMF (disabled)", DIRECTION_IN);
1706 trace_header("DTMF", DIRECTION_IN);
1707 add_trace("digit", NULL, "%c", param->dtmf);
1711 NOTE: vbox is now handled due to overlap state
1712 /* if vbox_play is done, the dtmf digits are just used as they come */
1714 if (e_action->index == ACTION_VBOX_PLAY) {
1715 /* concat dialing string */
1716 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1717 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1718 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1721 /* continue to process *X# sequences */
1725 /* check for *X# sequence */
1726 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1727 if (e_dtmf_time+3 < now) {
1728 /* the last digit was too far in the past to be a sequence */
1729 if (param->dtmf == '*')
1730 /* only start is allowed in the sequence */
1735 /* we have a sequence of digits, see what we got */
1736 if (param->dtmf == '*')
1738 else if (param->dtmf>='0' && param->dtmf<='9') {
1739 /* we need to have a star before we receive the digit of the sequence */
1740 if (e_dtmf_last == '*')
1741 e_dtmf_last = param->dtmf;
1742 } else if (param->dtmf == '#') {
1744 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1745 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1746 if (e_dtmf_last == '0') {
1750 /* processing keypad function */
1752 keypad_function(e_dtmf_last);
1758 /* set last time of dtmf */
1763 /* check for ## hookflash during dialing */
1765 if (e_action->index==ACTION_PASSWORD
1766 || e_action->index==ACTION_PASSWORD_WRITE)
1768 if (param->dtmf=='#') { /* current digit is '#' */
1769 if (e_state==EPOINT_STATE_IN_DISCONNECT
1770 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1784 /* dialing using dtmf digit */
1785 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1786 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1787 set_tone(portlist, "dialing");
1789 /* concat dialing string */
1790 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1791 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1792 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1798 /* port MESSAGE_CRYPT */
1799 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1801 /* send crypt response to cryptman */
1802 if (param->crypt.type == CR_MESSAGE_IND)
1803 cryptman_msg2man(param->crypt.data, param->crypt.len);
1805 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1808 /* port MESSAGE_OVERLAP */
1809 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1811 struct lcr_msg *message;
1813 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1815 /* signal to call tool */
1816 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1818 if (e_dialing_queue[0] && portlist) {
1819 /* send what we have not dialed yet, because we had no setup complete */
1820 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1821 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1822 SCPY(message->param.information.id, e_dialing_queue);
1823 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1824 message_put(message);
1825 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1826 e_dialing_queue[0] = '\0';
1828 /* check if pattern is available */
1829 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1830 /* indicate patterns */
1831 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1832 message_put(message);
1834 /* connect audio, if not already */
1835 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1836 message->param.audiopath = 1;
1837 message_put(message);
1839 /* indicate no patterns */
1840 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1841 message_put(message);
1843 /* disconnect audio, if not already */
1844 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1845 message->param.audiopath = 0;
1846 message_put(message);
1848 new_state(EPOINT_STATE_OUT_OVERLAP);
1849 /* if we are in a join */
1850 if (ea_endpoint->ep_join_id) {
1851 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1852 memcpy(&message->param, param, sizeof(union parameter));
1853 message_put(message);
1857 /* port MESSAGE_PROCEEDING */
1858 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1860 struct lcr_msg *message;
1862 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1864 /* signal to call tool */
1865 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1867 e_state = EPOINT_STATE_OUT_PROCEEDING;
1868 /* check if pattern is availatle */
1869 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1870 /* indicate patterns */
1871 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1872 message_put(message);
1874 /* connect audio, if not already */
1875 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1876 message->param.audiopath = 1;
1877 message_put(message);
1879 /* indicate no patterns */
1880 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1881 message_put(message);
1883 /* disconnect audio, if not already */
1884 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1885 message->param.audiopath = 0;
1886 message_put(message);
1888 /* if we are in a call */
1889 if (ea_endpoint->ep_join_id) {
1890 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1891 memcpy(&message->param, param, sizeof(union parameter));
1892 message_put(message);
1896 /* port MESSAGE_ALERTING */
1897 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1899 struct lcr_msg *message;
1901 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1903 /* signal to call tool */
1904 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1907 // set_tone(portlist, "hold");
1909 new_state(EPOINT_STATE_OUT_ALERTING);
1910 /* check if pattern is available */
1911 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1912 /* indicate patterns */
1913 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1914 message_put(message);
1916 /* connect audio, if not already */
1917 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1918 message->param.audiopath = 1;
1919 message_put(message);
1921 /* indicate no patterns */
1922 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1923 message_put(message);
1925 /* disconnect audio, if not already */
1926 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1927 message->param.audiopath = 0;
1928 message_put(message);
1930 /* if we are in a call */
1931 if (ea_endpoint->ep_join_id) {
1932 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1933 memcpy(&message->param, param, sizeof(union parameter));
1934 message_put(message);
1938 /* port MESSAGE_CONNECT */
1939 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1941 struct lcr_msg *message;
1943 unsigned int port_id = portlist->port_id;
1944 struct port_list *tportlist;
1946 struct interface *interface;
1949 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1951 /* signal to call tool */
1952 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1954 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1955 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1956 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1957 tportlist = ea_endpoint->ep_portlist;
1958 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1959 tportlist = tportlist->next;
1960 if (tportlist->port_id == port_id)
1961 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1962 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1963 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1964 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1965 message_put(message);
1966 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1967 ea_endpoint->free_portlist(tportlist);
1969 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1974 /* screen incoming connected id */
1975 interface = interface_first;
1977 if (!strcmp(e_connectinfo.interface, interface->name)) {
1980 interface = interface->next;
1983 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1985 /* screen connected name */
1987 SCPY(e_connectinfo.name, e_ext.name);
1989 /* add internal id to colp */
1990 SCPY(e_connectinfo.extension, e_ext.number);
1992 /* we store the connected port number */
1993 SCPY(e_extension_interface, e_connectinfo.interface);
1995 /* for internal and am calls, we get the extension's id */
1996 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1997 SCPY(e_connectinfo.id, e_ext.callerid);
1998 SCPY(e_connectinfo.extension, e_ext.number);
1999 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2000 e_connectinfo.ntype = e_ext.callerid_type;
2001 e_connectinfo.present = e_ext.callerid_present;
2003 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2004 e_connectinfo.itype = INFO_ITYPE_VBOX;
2005 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2008 new_state(EPOINT_STATE_CONNECT);
2010 /* set volume of rx and tx */
2011 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2012 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2013 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2014 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2015 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2016 message_put(message);
2019 unsched_timer(&e_cfnr_timeout);
2020 unsched_timer(&e_cfnr_call_timeout);
2021 if (e_ext.number[0])
2022 e_dtmf = 1; /* allow dtmf */
2025 /* other calls with no caller id (or not available for the extension) and force colp */
2026 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2027 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2028 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 */
2029 port = find_port_id(portlist->port_id);
2031 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2032 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2037 /* send connect to join */
2038 if (ea_endpoint->ep_join_id) {
2039 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2040 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2041 message_put(message);
2043 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2044 message->param.audiopath = 1;
2045 message_put(message);
2046 } else if (!e_adminid) {
2048 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2049 SCPY(e_ext.number, e_cbcaller);
2050 new_state(EPOINT_STATE_IN_OVERLAP);
2051 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2053 /* get extension's info about terminal */
2054 if (!read_extension(&e_ext, e_ext.number)) {
2055 /* extension doesn't exist */
2056 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2057 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2058 new_state(EPOINT_STATE_OUT_DISCONNECT);
2059 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2063 /* put prefix in front of e_cbdialing */
2064 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2065 SCPY(e_dialinginfo.id, buffer);
2066 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2067 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2069 /* use caller id (or if exist: id_next_call) for this call */
2070 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2071 SCPY(e_callerinfo.extension, e_ext.number);
2072 if (e_ext.id_next_call_present >= 0) {
2073 SCPY(e_callerinfo.id, e_ext.id_next_call);
2074 e_callerinfo.present = e_ext.id_next_call_present;
2075 e_callerinfo.ntype = e_ext.id_next_call_type;
2076 e_ext.id_next_call_present = -1;
2077 /* extension is written */
2078 write_extension(&e_ext, e_ext.number);
2080 SCPY(e_callerinfo.id, e_ext.callerid);
2081 e_callerinfo.present = e_ext.callerid_present;
2082 e_callerinfo.ntype = e_ext.callerid_type;
2084 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2086 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2089 /* check if caller id is NOT authenticated */
2090 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2091 /* make call state to enter password */
2092 new_state(EPOINT_STATE_IN_OVERLAP);
2093 e_action = &action_password_write;
2094 unsched_timer(&e_match_timeout);
2095 e_match_to_action = NULL;
2096 e_dialinginfo.id[0] = '\0';
2097 e_extdialing = strchr(e_dialinginfo.id, '\0');
2098 schedule_timer(&e_password_timeout, 20, 0);
2101 /* incoming call (callback) */
2102 e_ruleset = ruleset_main;
2104 e_rule = e_ruleset->rule_first;
2106 e_extdialing = e_dialinginfo.id;
2107 if (e_dialinginfo.id[0]) {
2108 set_tone(portlist, "dialing");
2111 set_tone(portlist, "dialpbx");
2114 } else { /* testcall */
2115 set_tone(portlist, "hold");
2118 /* start recording if enabled, not when answering machine answers */
2119 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)) {
2120 /* check if we are a terminal */
2121 if (e_ext.number[0] == '\0')
2122 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2124 port = find_port_id(portlist->port_id);
2126 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2131 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2132 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2134 struct lcr_msg *message;
2136 unsigned int port_id = portlist->port_id;
2140 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2142 /* signal to call tool */
2143 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2145 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2146 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2147 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2152 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);
2153 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2154 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2156 /* check if we have more than one portlist relation and we just ignore the disconnect */
2157 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2158 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2159 portlist = ea_endpoint->ep_portlist;
2161 if (portlist->port_id == port_id)
2163 portlist = portlist->next;
2166 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2167 if (message_type != MESSAGE_RELEASE) {
2168 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2169 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2170 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2171 message_put(message);
2172 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2174 ea_endpoint->free_portlist(portlist);
2175 return; /* one relation removed */
2177 if (e_state == EPOINT_STATE_CONNECT) {
2178 /* use cause from port after connect */
2179 cause = param->disconnectinfo.cause;
2180 location = param->disconnectinfo.location;
2182 /* use multipoint cause if no connect yet */
2183 if (e_multipoint_cause) {
2184 cause = e_multipoint_cause;
2185 location = e_multipoint_location;
2187 cause = CAUSE_NOUSER;
2188 location = LOCATION_PRIVATE_LOCAL;
2192 unsched_timer(&e_cfnr_timeout);
2193 unsched_timer(&e_cfnr_call_timeout);
2195 /* process hangup */
2196 process_hangup(e_join_cause, e_join_location);
2197 e_multipoint_cause = 0;
2198 e_multipoint_location = 0;
2200 if (message_type == MESSAGE_DISCONNECT) {
2201 /* tone to disconnected end */
2202 SPRINT(buffer, "cause_%02x", cause);
2203 if (ea_endpoint->ep_portlist)
2204 set_tone(ea_endpoint->ep_portlist, buffer);
2206 new_state(EPOINT_STATE_IN_DISCONNECT);
2209 if (ea_endpoint->ep_join_id) {
2210 int haspatterns = 0;
2211 /* check if pattern is available */
2212 if (ea_endpoint->ep_portlist)
2213 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2214 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
2215 && message_type != MESSAGE_RELEASE) // if we release, we are done
2218 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2219 /* indicate patterns */
2220 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2221 message_put(message);
2222 /* connect audio, if not already */
2223 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2224 message->param.audiopath = 1;
2225 message_put(message);
2226 /* send disconnect */
2227 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2228 memcpy(&message->param, param, sizeof(union parameter));
2229 message_put(message);
2230 /* disable encryption if disconnected */
2231 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2233 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2236 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2239 if (message_type == MESSAGE_RELEASE)
2240 ea_endpoint->free_portlist(portlist);
2241 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2242 return; /* must exit here */
2245 /* port MESSAGE_TIMEOUT */
2246 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2250 trace_header("TIMEOUT", DIRECTION_IN);
2251 message_type = MESSAGE_DISCONNECT;
2252 switch (param->state) {
2253 case PORT_STATE_OUT_SETUP:
2254 case PORT_STATE_OUT_OVERLAP:
2255 add_trace("state", NULL, "outgoing setup/dialing");
2257 /* no user responding */
2258 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2259 return; /* must exit here */
2261 case PORT_STATE_IN_SETUP:
2262 case PORT_STATE_IN_OVERLAP:
2263 add_trace("state", NULL, "incoming setup/dialing");
2264 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2265 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2268 case PORT_STATE_OUT_PROCEEDING:
2269 add_trace("state", NULL, "outgoing proceeding");
2271 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2272 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2273 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2274 return; /* must exit here */
2276 case PORT_STATE_IN_PROCEEDING:
2277 add_trace("state", NULL, "incoming proceeding");
2278 param->disconnectinfo.cause = CAUSE_NOUSER;
2279 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2282 case PORT_STATE_OUT_ALERTING:
2283 add_trace("state", NULL, "outgoing alerting");
2285 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2286 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2287 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2288 return; /* must exit here */
2290 case PORT_STATE_CONNECT:
2291 add_trace("state", NULL, "connect");
2293 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2294 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2295 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2296 return; /* must exit here */
2298 case PORT_STATE_IN_ALERTING:
2299 add_trace("state", NULL, "incoming alerting");
2300 param->disconnectinfo.cause = CAUSE_NOANSWER;
2301 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2304 case PORT_STATE_IN_DISCONNECT:
2305 case PORT_STATE_OUT_DISCONNECT:
2306 add_trace("state", NULL, "disconnect");
2308 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2309 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2310 return; /* must exit here */
2313 param->disconnectinfo.cause = 31; /* normal unspecified */
2314 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2317 /* release call, disconnect isdn */
2319 new_state(EPOINT_STATE_OUT_DISCONNECT);
2320 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2321 SCPY(e_tone, cause);
2323 set_tone(portlist, cause);
2324 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2325 portlist = portlist->next;
2327 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2330 /* port MESSAGE_NOTIFY */
2331 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2333 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2335 struct lcr_msg *message;
2336 const char *logtext = "";
2339 /* signal to call tool */
2340 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);
2341 if (param->notifyinfo.notify) {
2342 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2345 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2346 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2347 case INFO_NOTIFY_REMOTE_HOLD:
2348 case INFO_NOTIFY_USER_SUSPENDED:
2349 /* tell call about it */
2350 if (ea_endpoint->ep_join_id) {
2351 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2352 message->param.audiopath = 0;
2353 message_put(message);
2357 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2358 case INFO_NOTIFY_USER_RESUMED:
2359 /* set volume of rx and tx */
2360 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2361 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2363 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2364 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2365 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2366 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2367 message_put(message);
2369 /* set current tone */
2371 set_tone(portlist, e_tone);
2372 /* tell call about it */
2373 if (ea_endpoint->ep_join_id) {
2374 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2375 message->param.audiopath = 1;
2376 message_put(message);
2381 /* get name of notify */
2382 switch(param->notifyinfo.notify) {
2387 logtext = "USER_SUSPENDED";
2390 logtext = "BEARER_SERVICE_CHANGED";
2393 logtext = "USER_RESUMED";
2396 logtext = "CONFERENCE_ESTABLISHED";
2399 logtext = "CONFERENCE_DISCONNECTED";
2402 logtext = "OTHER_PARTY_ADDED";
2405 logtext = "ISOLATED";
2408 logtext = "REATTACHED";
2411 logtext = "OTHER_PARTY_ISOLATED";
2414 logtext = "OTHER_PARTY_REATTACHED";
2417 logtext = "OTHER_PARTY_SPLIT";
2420 logtext = "OTHER_PARTY_DISCONNECTED";
2423 logtext = "CONFERENCE_FLOATING";
2426 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2429 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2432 logtext = "CALL_IS_A_WAITING_CALL";
2435 logtext = "DIVERSION_ACTIVATED";
2438 logtext = "RESERVED_CT_1";
2441 logtext = "RESERVED_CT_2";
2444 logtext = "REVERSE_CHARGING";
2447 logtext = "REMOTE_HOLD";
2450 logtext = "REMOTE_RETRIEVAL";
2453 logtext = "CALL_IS_DIVERTING";
2456 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2461 /* notify call if available */
2462 if (ea_endpoint->ep_join_id) {
2463 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2464 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2465 message_put(message);
2470 /* port MESSAGE_FACILITY */
2471 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2473 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2475 struct lcr_msg *message;
2477 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2478 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2479 message_put(message);
2482 /* port MESSAGE_SUSPEND */
2483 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2484 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2486 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2488 /* epoint is now parked */
2489 ea_endpoint->ep_park = 1;
2490 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2491 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2493 /* remove port relation */
2494 ea_endpoint->free_portlist(portlist);
2497 /* port MESSAGE_RESUME */
2498 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2499 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2501 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2503 /* epoint is now resumed */
2504 ea_endpoint->ep_park = 0;
2509 /* port sends message to the endpoint
2511 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2513 struct port_list *portlist;
2515 portlist = ea_endpoint->ep_portlist;
2517 if (port_id == portlist->port_id)
2519 portlist = portlist->next;
2522 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);
2526 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2527 switch(message_type) {
2528 case MESSAGE_DATA: /* data from port */
2529 /* check if there is a call */
2530 if (!ea_endpoint->ep_join_id)
2532 /* continue if only one portlist */
2533 if (ea_endpoint->ep_portlist->next != NULL)
2535 /* forward message */
2536 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2539 case MESSAGE_TONE_EOF: /* tone is end of file */
2540 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2542 if (e_action->index == ACTION_VBOX_PLAY) {
2545 if (e_action->index == ACTION_EFI) {
2551 case MESSAGE_TONE_COUNTER: /* counter info received */
2552 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);
2554 if (e_action->index == ACTION_VBOX_PLAY) {
2555 e_vbox_counter = param->counter.current;
2556 if (param->counter.max >= 0)
2557 e_vbox_counter_max = param->counter.max;
2561 /* PORT sends SETUP message */
2563 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);
2564 if (e_state!=EPOINT_STATE_IDLE) {
2565 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2568 port_setup(portlist, message_type, param);
2571 /* PORT sends INFORMATION message */
2572 case MESSAGE_INFORMATION: /* additional digits received */
2573 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);
2574 port_information(portlist, message_type, param);
2577 /* PORT sends FACILITY message */
2578 case MESSAGE_FACILITY:
2579 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2580 port_facility(portlist, message_type, param);
2583 /* PORT sends DTMF message */
2584 case MESSAGE_DTMF: /* dtmf digits received */
2585 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);
2586 port_dtmf(portlist, message_type, param);
2589 /* PORT sends CRYPT message */
2590 case MESSAGE_CRYPT: /* crypt response received */
2591 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2592 port_crypt(portlist, message_type, param);
2595 /* PORT sends MORE message */
2596 case MESSAGE_OVERLAP:
2597 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);
2598 if (e_state != EPOINT_STATE_OUT_SETUP) {
2599 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);
2602 port_overlap(portlist, message_type, param);
2605 /* PORT sends PROCEEDING message */
2606 case MESSAGE_PROCEEDING: /* port is proceeding */
2607 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);
2608 if (e_state!=EPOINT_STATE_OUT_SETUP
2609 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2610 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);
2613 port_proceeding(portlist, message_type, param);
2616 /* PORT sends ALERTING message */
2617 case MESSAGE_ALERTING:
2618 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);
2619 if (e_state!=EPOINT_STATE_OUT_SETUP
2620 && e_state!=EPOINT_STATE_OUT_OVERLAP
2621 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2622 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);
2625 port_alerting(portlist, message_type, param);
2628 /* PORT sends CONNECT message */
2629 case MESSAGE_CONNECT:
2630 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);
2631 if (e_state!=EPOINT_STATE_OUT_SETUP
2632 && e_state!=EPOINT_STATE_OUT_OVERLAP
2633 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2634 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2635 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2638 port_connect(portlist, message_type, param);
2641 /* PORT sends DISCONNECT message */
2642 case MESSAGE_DISCONNECT: /* port is disconnected */
2643 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);
2644 port_disconnect_release(portlist, message_type, param);
2647 /* PORT sends a RELEASE message */
2648 case MESSAGE_RELEASE: /* port releases */
2649 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);
2650 /* portlist is release at port_disconnect_release, thanx Paul */
2651 port_disconnect_release(portlist, message_type, param);
2654 /* PORT sends a TIMEOUT message */
2655 case MESSAGE_TIMEOUT:
2656 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);
2657 port_timeout(portlist, message_type, param);
2658 break; /* release */
2660 /* PORT sends a NOTIFY message */
2661 case MESSAGE_NOTIFY:
2662 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);
2663 port_notify(portlist, message_type, param);
2666 /* PORT sends a SUSPEND message */
2667 case MESSAGE_SUSPEND:
2668 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);
2669 port_suspend(portlist, message_type, param);
2670 break; /* suspend */
2672 /* PORT sends a RESUME message */
2673 case MESSAGE_RESUME:
2674 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);
2675 port_resume(portlist, message_type, param);
2679 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2680 /* port assigns bchannel */
2681 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2682 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);
2683 /* only one port is expected to be connected to bchannel */
2684 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2685 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2691 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);
2694 /* Note: this endpoint may be destroyed, so we MUST return */
2698 /* messages from join
2700 /* join MESSAGE_CRYPT */
2701 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2703 switch(param->crypt.type) {
2704 /* message from remote port to "crypt manager" */
2705 case CU_ACTK_REQ: /* activate key-exchange */
2706 case CU_ACTS_REQ: /* activate shared key */
2707 case CU_DACT_REQ: /* deactivate */
2708 case CU_INFO_REQ: /* request last info message */
2709 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2712 /* message from "crypt manager" to user */
2713 case CU_ACTK_CONF: /* key-echange done */
2714 case CU_ACTS_CONF: /* shared key done */
2715 case CU_DACT_CONF: /* deactivated */
2716 case CU_DACT_IND: /* deactivated */
2717 case CU_ERROR_IND: /* receive error message */
2718 case CU_INFO_IND: /* receive info message */
2719 case CU_INFO_CONF: /* receive info message */
2720 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2724 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);
2728 /* join MESSAGE_INFORMATION */
2729 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2731 struct lcr_msg *message;
2736 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2737 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2738 message_put(message);
2739 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2740 portlist = portlist->next;
2744 /* join MESSAGE_FACILITY */
2745 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2747 struct lcr_msg *message;
2749 if (!e_ext.facility && e_ext.number[0]) {
2754 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2755 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2756 message_put(message);
2757 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2758 portlist = portlist->next;
2762 /* join MESSAGE_MORE */
2763 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2765 struct lcr_msg *message;
2767 new_state(EPOINT_STATE_IN_OVERLAP);
2770 if (e_join_pattern && e_ext.own_setup) {
2771 /* disconnect audio */
2772 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2773 message->param.audiopath = 0;
2774 message_put(message);
2776 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2777 if (e_dialinginfo.id[0])
2778 set_tone(portlist, "dialing");
2780 set_tone(portlist, "dialtone");
2783 if (e_dialinginfo.id[0]) {
2784 set_tone(portlist, "dialing");
2786 if (e_ext.number[0])
2787 set_tone(portlist, "dialpbx");
2789 set_tone(portlist, "dialtone");
2793 /* join MESSAGE_PROCEEDING */
2794 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2796 struct lcr_msg *message;
2798 new_state(EPOINT_STATE_IN_PROCEEDING);
2800 /* own proceeding tone */
2801 if (e_join_pattern) {
2802 /* connect / disconnect audio */
2803 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2804 if (e_ext.own_proceeding)
2805 message->param.audiopath = 0;
2807 message->param.audiopath = 1;
2808 message_put(message);
2810 // UCPY(e_join_tone, "proceeding");
2812 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2813 message_put(message);
2814 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2816 set_tone(portlist, "proceeding");
2819 /* join MESSAGE_ALERTING */
2820 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2822 struct lcr_msg *message;
2824 new_state(EPOINT_STATE_IN_ALERTING);
2826 /* own alerting tone */
2827 if (e_join_pattern) {
2828 /* connect / disconnect audio */
2829 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2830 if (e_ext.own_alerting)
2831 message->param.audiopath = 0;
2833 message->param.audiopath = 1;
2834 message_put(message);
2837 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2838 message_put(message);
2839 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2841 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2842 set_tone(portlist, "ringing");
2845 if (e_ext.number[0])
2846 set_tone(portlist, "ringpbx");
2848 set_tone(portlist, "ringing");
2850 if (e_ext.number[0])
2851 e_dtmf = 1; /* allow dtmf */
2854 /* join MESSAGE_CONNECT */
2855 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2857 struct lcr_msg *message;
2860 new_state(EPOINT_STATE_CONNECT);
2861 // UCPY(e_join_tone, "");
2863 if (e_ext.number[0])
2864 e_dtmf = 1; /* allow dtmf */
2867 unsched_timer(&e_powerdial_timeout);
2868 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2870 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2871 memcpy(&message->param, param, sizeof(union parameter));
2873 /* screen clip if prefix is required */
2874 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2875 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2876 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2877 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2880 /* use internal caller id */
2881 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2882 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2883 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2886 /* handle restricted caller ids */
2887 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);
2888 /* display callerid if desired for extension */
2889 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));
2891 /* use conp, if enabld */
2892 // if (!e_ext.centrex)
2893 // message->param.connectinfo.name[0] = '\0';
2896 message_put(message);
2897 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2899 set_tone(portlist, NULL);
2901 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2902 message->param.audiopath = 1;
2903 message_put(message);
2908 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2909 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2912 struct lcr_msg *message;
2913 struct port_list *portlist = NULL;
2917 /* be sure that we are active */
2919 e_tx_state = NOTIFY_STATE_ACTIVE;
2921 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2922 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2923 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2925 /* set time for power dialing */
2926 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2929 /* set redial tone */
2930 if (ea_endpoint->ep_portlist) {
2933 set_tone(ea_endpoint->ep_portlist, "redial");
2934 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);
2935 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2936 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2937 new_state(EPOINT_STATE_IN_PROCEEDING);
2938 if (ea_endpoint->ep_portlist) {
2939 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2940 message_put(message);
2941 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2943 /* caused the error, that the first knock sound was not there */
2944 /* set_tone(portlist, "proceeding"); */
2946 /* send display of powerdialing */
2947 if (e_ext.display_dialing) {
2948 portlist = ea_endpoint->ep_portlist;
2950 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2952 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2954 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2955 message_put(message);
2956 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2957 portlist = portlist->next;
2967 if ((e_state!=EPOINT_STATE_CONNECT
2968 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2969 && e_state!=EPOINT_STATE_IN_OVERLAP
2970 && e_state!=EPOINT_STATE_IN_PROCEEDING
2971 && e_state!=EPOINT_STATE_IN_ALERTING)
2972 || !ea_endpoint->ep_portlist) { /* or no port */
2973 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
2974 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
2975 return; /* must exit here */
2978 if (!e_join_cause) {
2979 e_join_cause = param->disconnectinfo.cause;
2980 e_join_location = param->disconnectinfo.location;
2983 /* on release we need the audio again! */
2984 if (message_type == MESSAGE_RELEASE) {
2986 ea_endpoint->ep_join_id = 0;
2988 /* disconnect and select tone */
2989 new_state(EPOINT_STATE_OUT_DISCONNECT);
2990 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2991 /* if own_cause, we must release the join */
2992 if (e_ext.own_cause /* own cause */
2993 || !e_join_pattern) { /* no patterns */
2994 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);
2995 if (message_type != MESSAGE_RELEASE)
2996 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2998 } else { /* else we enable audio */
2999 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3000 message->param.audiopath = 1;
3001 message_put(message);
3003 /* send disconnect message */
3004 SCPY(e_tone, cause);
3005 portlist = ea_endpoint->ep_portlist;
3007 set_tone(portlist, cause);
3008 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3009 portlist = portlist->next;
3013 /* join MESSAGE_SETUP */
3014 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3016 struct lcr_msg *message;
3017 // struct interface *interface;
3019 /* if we already in setup state, we just update the dialing with new digits */
3020 if (e_state == EPOINT_STATE_OUT_SETUP
3021 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3022 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3023 /* if digits changed, what we have already dialed */
3024 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3025 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);
3026 /* release all ports */
3027 while((portlist = ea_endpoint->ep_portlist)) {
3028 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3029 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3030 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3031 message_put(message);
3032 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3033 ea_endpoint->free_portlist(portlist);
3036 /* disconnect audio */
3037 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3038 message->param.audiopath = 0;
3039 message_put(message);
3041 /* get dialing info */
3042 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3043 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3044 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3045 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3046 new_state(EPOINT_STATE_OUT_OVERLAP);
3049 schedule_timer(&e_redial_timeout, 1, 0);
3052 /* if we have a pending redial, so we just adjust the dialing number */
3053 if (e_redial_timeout.active) {
3054 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);
3055 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3058 if (!ea_endpoint->ep_portlist) {
3059 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3061 if (ea_endpoint->ep_portlist->next) {
3062 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3064 if (e_state == EPOINT_STATE_OUT_SETUP) {
3066 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);
3067 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3070 /* get what we have not dialed yet */
3071 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));
3072 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3073 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3074 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3075 message_put(message);
3076 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3078 /* always store what we have dialed or queued */
3079 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3083 if (e_state != EPOINT_STATE_IDLE) {
3084 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3087 /* if an internal extension is dialed, copy that number */
3088 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3089 SCPY(e_ext.number, param->setup.dialinginfo.id);
3090 /* if an internal extension is dialed, get extension's info about caller */
3091 if (e_ext.number[0]) {
3092 if (!read_extension(&e_ext, e_ext.number)) {
3093 e_ext.number[0] = '\0';
3094 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3098 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3099 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3100 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3101 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3103 /* process (voice over) data calls */
3104 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3105 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3106 memset(&e_capainfo, 0, sizeof(e_capainfo));
3107 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3108 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3109 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3112 new_state(EPOINT_STATE_OUT_SETUP);
3113 /* call special setup routine */
3117 /* join MESSAGE_mISDNSIGNAL */
3118 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3120 struct lcr_msg *message;
3123 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3124 memcpy(&message->param, param, sizeof(union parameter));
3125 message_put(message);
3126 portlist = portlist->next;
3130 /* join MESSAGE_NOTIFY */
3131 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3133 struct lcr_msg *message;
3136 if (param->notifyinfo.notify) {
3137 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3138 // /* if notification was generated locally, we turn hold music on/off */
3139 // if (param->notifyinfo.local)
3140 // 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)
3144 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3145 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3147 set_tone(portlist, "");
3148 portlist = portlist->next;
3151 portlist = ea_endpoint->ep_portlist;
3156 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3158 set_tone(portlist, "hold");
3159 portlist = portlist->next;
3161 portlist = ea_endpoint->ep_portlist;
3166 /* save new state */
3167 e_tx_state = new_state;
3170 /* notify port(s) about it */
3172 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3173 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3174 /* handle restricted caller ids */
3175 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3176 /* display callerid if desired for extension */
3177 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));
3178 message_put(message);
3179 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3180 portlist = portlist->next;
3184 /* JOIN sends messages to the endpoint
3186 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3188 struct port_list *portlist;
3189 struct lcr_msg *message;
3192 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3196 portlist = ea_endpoint->ep_portlist;
3198 /* send MESSAGE_DATA to port */
3199 if (message_type == MESSAGE_DATA) {
3200 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3201 /* skip if no port relation */
3204 /* skip if more than one port relation */
3207 /* forward audio data to port */
3208 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3213 // 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);
3214 switch(message_type) {
3215 /* JOIN SENDS TONE message */
3217 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);
3218 set_tone(portlist, param->tone.name);
3221 /* JOIN SENDS CRYPT message */
3223 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);
3224 join_crypt(portlist, message_type, param);
3227 /* JOIN sends INFORMATION message */
3228 case MESSAGE_INFORMATION:
3229 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);
3230 join_information(portlist, message_type, param);
3233 /* JOIN sends FACILITY message */
3234 case MESSAGE_FACILITY:
3235 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);
3236 join_facility(portlist, message_type, param);
3239 /* JOIN sends OVERLAP message */
3240 case MESSAGE_OVERLAP:
3241 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);
3242 if (e_state!=EPOINT_STATE_IN_SETUP
3243 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3244 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3247 join_overlap(portlist, message_type, param);
3250 /* JOIN sends PROCEEDING message */
3251 case MESSAGE_PROCEEDING:
3252 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);
3253 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3254 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3257 join_proceeding(portlist, message_type, param);
3260 /* JOIN sends ALERTING message */
3261 case MESSAGE_ALERTING:
3262 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);
3263 if (e_state!=EPOINT_STATE_IN_OVERLAP
3264 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3265 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3268 join_alerting(portlist, message_type, param);
3271 /* JOIN sends CONNECT message */
3272 case MESSAGE_CONNECT:
3273 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);
3274 if (e_state!=EPOINT_STATE_IN_OVERLAP
3275 && e_state!=EPOINT_STATE_IN_PROCEEDING
3276 && e_state!=EPOINT_STATE_IN_ALERTING) {
3277 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3280 join_connect(portlist, message_type, param);
3283 /* JOIN sends DISCONNECT/RELEASE message */
3284 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3285 case MESSAGE_RELEASE: /* JOIN releases */
3286 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);
3287 join_disconnect_release(message_type, param);
3290 /* JOIN sends SETUP message */
3292 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);
3293 join_setup(portlist, message_type, param);
3296 /* JOIN sends special mISDNSIGNAL message */
3297 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3298 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);
3299 join_mISDNsignal(portlist, message_type, param);
3303 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3304 /* JOIN requests bchannel */
3305 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3306 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);
3307 /* only one port is expected to be connected to bchannel */
3314 set_tone(portlist, NULL);
3315 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3316 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3320 /* JOIN has pattern available */
3321 case MESSAGE_PATTERN: /* indicating pattern available */
3322 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);
3323 if (!e_join_pattern) {
3324 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3328 set_tone(portlist, NULL);
3329 portlist = portlist->next;
3331 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3332 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3333 message->param.audiopath = 1;
3334 message_put(message);
3338 /* JOIN has no pattern available */
3339 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3340 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);
3341 if (e_join_pattern) {
3342 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3344 /* disconnect our audio tx and rx */
3345 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3346 message->param.audiopath = 0;
3347 message_put(message);
3352 /* JOIN (dunno at the moment) */
3353 case MESSAGE_REMOTE_AUDIO:
3354 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);
3355 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3356 message->param.audiopath = param->channel;
3357 message_put(message);
3361 /* JOIN sends a notify message */
3362 case MESSAGE_NOTIFY:
3363 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);
3364 join_notify(portlist, message_type, param);
3367 /* JOIN wants keypad / dtmf */
3368 case MESSAGE_ENABLEKEYPAD:
3369 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);
3372 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3377 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);
3382 /* pick_join will connect the first incoming call found. the endpoint
3383 * will receivce a MESSAGE_CONNECT.
3385 int match_list(char *list, char *item)
3387 char *end, *next = NULL;
3389 /* no list make matching */
3394 /* eliminate white spaces */
3395 while (*list <= ' ')
3401 /* if end of list is reached, we return */
3402 if (list[0] == '\0')
3404 /* if we have more than one entry (left) */
3405 if ((end = strchr(list, ',')))
3408 next = end = strchr(list, '\0');
3409 while (*(end-1) <= ' ')
3411 /* if string part matches item */
3412 if (!strncmp(list, item, end-list))
3418 void EndpointAppPBX::pick_join(char *extensions)
3420 struct lcr_msg *message;
3421 struct port_list *portlist;
3423 class EndpointAppPBX *eapp, *found;
3425 class JoinPBX *joinpbx;
3426 struct join_relation *relation;
3429 /* find an endpoint that is ringing internally or vbox with higher priority */
3432 eapp = apppbx_first;
3434 if (eapp!=this && ea_endpoint->ep_portlist) {
3435 portlist = eapp->ea_endpoint->ep_portlist;
3437 if ((port = find_port_id(portlist->port_id))) {
3438 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3439 if (match_list(extensions, eapp->e_ext.number)) {
3445 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3446 && port->p_state==PORT_STATE_OUT_ALERTING)
3447 if (match_list(extensions, eapp->e_ext.number)) {
3451 portlist = portlist->next;
3459 /* if no endpoint found */
3461 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);
3463 set_tone(ea_endpoint->ep_portlist, "cause_10");
3464 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3465 new_state(EPOINT_STATE_OUT_DISCONNECT);
3470 if (ea_endpoint->ep_join_id) {
3471 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3474 if (!eapp->ea_endpoint->ep_join_id) {
3475 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3478 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3480 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3483 if (join->j_type != JOIN_TYPE_PBX) {
3484 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3487 joinpbx = (class JoinPBX *)join;
3488 relation = joinpbx->j_relation;
3490 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3493 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3494 relation = relation->next;
3496 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3501 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3503 if (options.deb & DEBUG_EPOINT) {
3504 class Join *debug_c = join_first;
3505 class Endpoint *debug_e = epoint_first;
3506 class Port *debug_p = port_first;
3508 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3510 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3512 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3513 debug_c = debug_c->next;
3515 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3517 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3518 debug_e = debug_e->next;
3520 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3522 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3523 debug_p = debug_p->next;
3528 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3529 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3530 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3532 /* connnecting our endpoint */
3533 new_state(EPOINT_STATE_CONNECT);
3534 if (e_ext.number[0])
3536 set_tone(ea_endpoint->ep_portlist, NULL);
3538 /* now we send a release to the ringing endpoint */
3539 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3540 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3541 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3542 message_put(message);
3544 /* we send a connect to the join with our caller id */
3545 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3546 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3547 message->param.connectinfo.present = e_callerinfo.present;
3548 message->param.connectinfo.screen = e_callerinfo.screen;
3549 message->param.connectinfo.itype = e_callerinfo.itype;
3550 message->param.connectinfo.ntype = e_callerinfo.ntype;
3551 message_put(message);
3553 /* we send a connect to our port with the remote callerid */
3554 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3555 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3556 message->param.connectinfo.present = eapp->e_callerinfo.present;
3557 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3558 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3559 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3560 /* handle restricted caller ids */
3561 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);
3562 /* display callerid if desired for extension */
3563 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));
3564 message_put(message);
3566 /* we send a connect to the audio path (not for vbox) */
3567 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3568 message->param.audiopath = 1;
3569 message_put(message);
3571 /* beeing paranoid, we make call update */
3572 trigger_work(&joinpbx->j_updatebridge);
3574 if (options.deb & DEBUG_EPOINT) {
3575 class Join *debug_c = join_first;
3576 class Endpoint *debug_e = epoint_first;
3577 class Port *debug_p = port_first;
3579 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3581 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3583 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3584 debug_c = debug_c->next;
3586 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3588 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3589 debug_e = debug_e->next;
3591 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3593 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3594 debug_p = debug_p->next;
3600 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3602 void EndpointAppPBX::join_join(void)
3604 struct lcr_msg *message;
3605 struct join_relation *our_relation, *other_relation;
3606 struct join_relation **our_relation_pointer, **other_relation_pointer;
3607 class Join *our_join, *other_join;
3608 class JoinPBX *our_joinpbx, *other_joinpbx;
3609 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3610 class Port *our_port, *other_port;
3611 class Pdss1 *our_pdss1, *other_pdss1;
3613 /* are we a candidate to join a join? */
3614 our_join = find_join_id(ea_endpoint->ep_join_id);
3616 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3619 if (our_join->j_type != JOIN_TYPE_PBX) {
3620 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3623 our_joinpbx = (class JoinPBX *)our_join;
3624 if (!ea_endpoint->ep_portlist) {
3625 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3628 if (!e_ext.number[0]) {
3629 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3632 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3634 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3637 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3638 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3641 our_pdss1 = (class Pdss1 *)our_port;
3643 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3644 other_eapp = apppbx_first;
3646 if (other_eapp == this) {
3647 other_eapp = other_eapp->next;
3650 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);
3651 if (other_eapp->e_ext.number[0] /* has terminal */
3652 && other_eapp->ea_endpoint->ep_portlist /* has port */
3653 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3654 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3655 if (other_port) { /* port still exists */
3656 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3657 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3658 other_pdss1 = (class Pdss1 *)other_port;
3659 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);
3660 if (other_pdss1->p_m_hold /* port is on hold */
3661 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3662 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3665 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3668 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3671 other_eapp = other_eapp->next;
3674 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3677 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3679 /* if we have the same join */
3680 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3681 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3684 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3686 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3689 if (other_join->j_type != JOIN_TYPE_PBX) {
3690 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3693 other_joinpbx = (class JoinPBX *)other_join;
3694 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3695 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3699 /* remove relation to endpoint for join on hold */
3700 other_relation = other_joinpbx->j_relation;
3701 other_relation_pointer = &other_joinpbx->j_relation;
3702 while(other_relation) {
3703 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3704 /* detach other endpoint on hold */
3705 *other_relation_pointer = other_relation->next;
3706 FREE(other_relation, sizeof(struct join_relation));
3708 other_relation = *other_relation_pointer;
3709 other_eapp->ea_endpoint->ep_join_id = 0;
3713 /* change join/hold pointer of endpoint to the new join */
3714 temp_epoint = find_epoint_id(other_relation->epoint_id);
3716 if (temp_epoint->ep_join_id == other_join->j_serial)
3717 temp_epoint->ep_join_id = our_join->j_serial;
3720 other_relation_pointer = &other_relation->next;
3721 other_relation = other_relation->next;
3723 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3725 /* join call relations */
3726 our_relation = our_joinpbx->j_relation;
3727 our_relation_pointer = &our_joinpbx->j_relation;
3728 while(our_relation) {
3729 our_relation_pointer = &our_relation->next;
3730 our_relation = our_relation->next;
3732 *our_relation_pointer = other_joinpbx->j_relation;
3733 other_joinpbx->j_relation = NULL;
3734 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3736 /* release endpoint on hold */
3737 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3738 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3739 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3740 message_put(message);
3742 /* if we are not a partyline, we get partyline state from other join */
3743 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3745 /* remove empty join */
3747 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3749 /* mixer must update */
3750 trigger_work(&our_joinpbx->j_updatebridge);
3752 /* we send a retrieve to that endpoint */
3753 // mixer will update the hold-state of the join and send it to the endpoints is changes
3757 /* check if we have an external call
3758 * this is used to check for encryption ability
3760 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3762 struct join_relation *relation;
3764 class JoinPBX *joinpbx;
3765 class Endpoint *epoint;
3767 /* some paranoia check */
3768 if (!ea_endpoint->ep_portlist) {
3769 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3770 *errstr = "No Call";
3773 if (!e_ext.number[0]) {
3774 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3775 *errstr = "No Call";
3779 /* check if we have a join with 2 parties */
3780 join = find_join_id(ea_endpoint->ep_join_id);
3782 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3783 *errstr = "No Call";
3786 if (join->j_type != JOIN_TYPE_PBX) {
3787 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3788 *errstr = "No PBX Call";
3791 joinpbx = (class JoinPBX *)join;
3792 relation = joinpbx->j_relation;
3794 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3795 *errstr = "No Call";
3798 if (!relation->next) {
3799 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3800 *errstr = "No Call";
3803 if (relation->next->next) {
3804 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3805 *errstr = "Err: Conference";
3808 if (relation->epoint_id == ea_endpoint->ep_serial) {
3809 relation = relation->next;
3810 if (relation->epoint_id == ea_endpoint->ep_serial) {
3811 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3812 *errstr = "Software Error";
3817 /* check remote port for external call */
3818 epoint = find_epoint_id(relation->epoint_id);
3820 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3821 *errstr = "No Call";
3824 if (!epoint->ep_portlist) {
3825 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3826 *errstr = "No Call";
3829 *port = find_port_id(epoint->ep_portlist->port_id);
3831 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3832 *errstr = "No Call";
3835 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3836 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3837 *errstr = "No Ext Call";
3840 if ((*port)->p_state != PORT_STATE_CONNECT) {
3841 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3842 *errstr = "No Ext Connect";
3848 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3850 const char *logtext = "unknown";
3853 switch(message_type) {
3855 trace_header("SETUP", dir);
3856 if (dir == DIRECTION_OUT)
3857 add_trace("to", NULL, "CH(%lu)", port_id);
3858 if (dir == DIRECTION_IN)
3859 add_trace("from", NULL, "CH(%lu)", port_id);
3860 if (param->setup.callerinfo.extension[0])
3861 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3862 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3863 switch(param->setup.callerinfo.present) {
3864 case INFO_PRESENT_RESTRICTED:
3865 add_trace("caller id", "present", "restricted");
3867 case INFO_PRESENT_ALLOWED:
3868 add_trace("caller id", "present", "allowed");
3871 add_trace("caller id", "present", "not available");
3873 if (param->setup.callerinfo.ntype2) {
3874 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3875 switch(param->setup.callerinfo.present) {
3876 case INFO_PRESENT_RESTRICTED:
3877 add_trace("caller id2", "present", "restricted");
3879 case INFO_PRESENT_ALLOWED:
3880 add_trace("caller id2", "present", "allowed");
3883 add_trace("caller id2", "present", "not available");
3886 if (param->setup.redirinfo.id[0]) {
3887 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3888 switch(param->setup.redirinfo.present) {
3889 case INFO_PRESENT_RESTRICTED:
3890 add_trace("redir'ing", "present", "restricted");
3892 case INFO_PRESENT_ALLOWED:
3893 add_trace("redir'ing", "present", "allowed");
3896 add_trace("redir'ing", "present", "not available");
3899 if (param->setup.dialinginfo.id[0])
3900 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3901 if (param->setup.dialinginfo.keypad[0])
3902 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3903 if (param->setup.dialinginfo.display[0])
3904 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3905 if (param->setup.dialinginfo.sending_complete)
3906 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3910 case MESSAGE_OVERLAP:
3911 trace_header("SETUP ACKNOWLEDGE", dir);
3912 if (dir == DIRECTION_OUT)
3913 add_trace("to", NULL, "CH(%lu)", port_id);
3914 if (dir == DIRECTION_IN)
3915 add_trace("from", NULL, "CH(%lu)", port_id);
3919 case MESSAGE_PROCEEDING:
3920 trace_header("PROCEEDING", dir);
3921 if (dir == DIRECTION_OUT)
3922 add_trace("to", NULL, "CH(%lu)", port_id);
3923 if (dir == DIRECTION_IN)
3924 add_trace("from", NULL, "CH(%lu)", port_id);
3928 case MESSAGE_ALERTING:
3929 trace_header("ALERTING", dir);
3930 if (dir == DIRECTION_OUT)
3931 add_trace("to", NULL, "CH(%lu)", port_id);
3932 if (dir == DIRECTION_IN)
3933 add_trace("from", NULL, "CH(%lu)", port_id);
3937 case MESSAGE_CONNECT:
3938 trace_header("CONNECT", dir);
3939 if (dir == DIRECTION_OUT)
3940 add_trace("to", NULL, "CH(%lu)", port_id);
3941 if (dir == DIRECTION_IN)
3942 add_trace("from", NULL, "CH(%lu)", port_id);
3943 if (param->connectinfo.extension[0])
3944 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3945 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3946 switch(param->connectinfo.present) {
3947 case INFO_PRESENT_RESTRICTED:
3948 add_trace("connect id", "present", "restricted");
3950 case INFO_PRESENT_ALLOWED:
3951 add_trace("connect id", "present", "allowed");
3954 add_trace("connect id", "present", "not available");
3956 if (param->connectinfo.display[0])
3957 add_trace("display", NULL, "%s", param->connectinfo.display);
3961 case MESSAGE_DISCONNECT:
3962 case MESSAGE_RELEASE:
3963 if (message_type == MESSAGE_DISCONNECT)
3964 trace_header("DISCONNECT", dir);
3966 trace_header("RELEASE", dir);
3967 if (dir == DIRECTION_OUT)
3968 add_trace("to", NULL, "CH(%lu)", port_id);
3969 if (dir == DIRECTION_IN)
3970 add_trace("from", NULL, "CH(%lu)", port_id);
3971 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3972 switch(param->disconnectinfo.location) {
3974 add_trace("cause", "location", "0-User");
3976 case LOCATION_PRIVATE_LOCAL:
3977 add_trace("cause", "location", "1-Local-PBX");
3979 case LOCATION_PUBLIC_LOCAL:
3980 add_trace("cause", "location", "2-Local-Exchange");
3982 case LOCATION_TRANSIT:
3983 add_trace("cause", "location", "3-Transit");
3985 case LOCATION_PUBLIC_REMOTE:
3986 add_trace("cause", "location", "4-Remote-Exchange");
3988 case LOCATION_PRIVATE_REMOTE:
3989 add_trace("cause", "location", "5-Remote-PBX");
3991 case LOCATION_INTERNATIONAL:
3992 add_trace("cause", "location", "7-International-Exchange");
3994 case LOCATION_BEYOND:
3995 add_trace("cause", "location", "10-Beyond-Interworking");
3998 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4000 if (param->disconnectinfo.display[0])
4001 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4005 case MESSAGE_NOTIFY:
4006 switch(param->notifyinfo.notify) {
4011 logtext = "USER_SUSPENDED";
4014 logtext = "BEARER_SERVICE_CHANGED";
4017 logtext = "USER_RESUMED";
4020 logtext = "CONFERENCE_ESTABLISHED";
4023 logtext = "CONFERENCE_DISCONNECTED";
4026 logtext = "OTHER_PARTY_ADDED";
4029 logtext = "ISOLATED";
4032 logtext = "REATTACHED";
4035 logtext = "OTHER_PARTY_ISOLATED";
4038 logtext = "OTHER_PARTY_REATTACHED";
4041 logtext = "OTHER_PARTY_SPLIT";
4044 logtext = "OTHER_PARTY_DISCONNECTED";
4047 logtext = "CONFERENCE_FLOATING";
4050 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4053 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4056 logtext = "CALL_IS_A_WAITING_CALL";
4059 logtext = "DIVERSION_ACTIVATED";
4062 logtext = "RESERVED_CT_1";
4065 logtext = "RESERVED_CT_2";
4068 logtext = "REVERSE_CHARGING";
4071 logtext = "REMOTE_HOLD";
4074 logtext = "REMOTE_RETRIEVAL";
4077 logtext = "CALL_IS_DIVERTING";
4080 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4084 trace_header("NOTIFY", dir);
4085 if (dir == DIRECTION_OUT)
4086 add_trace("to", NULL, "CH(%lu)", port_id);
4087 if (dir == DIRECTION_IN)
4088 add_trace("from", NULL, "CH(%lu)", port_id);
4089 if (param->notifyinfo.notify)
4090 add_trace("indicator", NULL, "%s", logtext);
4091 if (param->notifyinfo.id[0]) {
4092 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4093 switch(param->notifyinfo.present) {
4094 case INFO_PRESENT_RESTRICTED:
4095 add_trace("redir'on", "present", "restricted");
4097 case INFO_PRESENT_ALLOWED:
4098 add_trace("redir'on", "present", "allowed");
4101 add_trace("redir'on", "present", "not available");
4104 if (param->notifyinfo.display[0])
4105 add_trace("display", NULL, "%s", param->notifyinfo.display);
4109 case MESSAGE_INFORMATION:
4110 trace_header("INFORMATION", dir);
4111 if (dir == DIRECTION_OUT)
4112 add_trace("to", NULL, "CH(%lu)", port_id);
4113 if (dir == DIRECTION_IN)
4114 add_trace("from", NULL, "CH(%lu)", port_id);
4115 if (param->information.id[0])
4116 add_trace("dialing", NULL, "%s", param->information.id);
4117 if (param->information.display[0])
4118 add_trace("display", NULL, "%s", param->information.display);
4119 if (param->information.sending_complete)
4120 add_trace("complete", NULL, "true", param->information.sending_complete);
4124 case MESSAGE_FACILITY:
4125 trace_header("FACILITY", dir);
4126 if (dir == DIRECTION_OUT)
4127 add_trace("to", NULL, "CH(%lu)", port_id);
4128 if (dir == DIRECTION_IN)
4129 add_trace("from", NULL, "CH(%lu)", port_id);
4134 trace_header("TONE", dir);
4135 if (dir == DIRECTION_OUT)
4136 add_trace("to", NULL, "CH(%lu)", port_id);
4137 if (dir == DIRECTION_IN)
4138 add_trace("from", NULL, "CH(%lu)", port_id);
4139 if (param->tone.name[0]) {
4140 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4141 add_trace("name", NULL, "%s", param->tone.name);
4143 add_trace("off", NULL, NULL);
4147 case MESSAGE_SUSPEND:
4148 case MESSAGE_RESUME:
4149 if (message_type == MESSAGE_SUSPEND)
4150 trace_header("SUSPEND", dir);
4152 trace_header("RESUME", dir);
4153 if (dir == DIRECTION_OUT)
4154 add_trace("to", NULL, "CH(%lu)", port_id);
4155 if (dir == DIRECTION_IN)
4156 add_trace("from", NULL, "CH(%lu)", port_id);
4157 if (param->parkinfo.len)
4158 add_trace("length", NULL, "%d", param->parkinfo.len);
4163 case MESSAGE_BCHANNEL:
4164 trace_header("BCHANNEL", dir);
4165 switch(param->bchannel.type) {
4166 case BCHANNEL_REQUEST:
4167 add_trace("type", NULL, "request");
4169 case BCHANNEL_ASSIGN:
4170 add_trace("type", NULL, "assign");
4172 case BCHANNEL_ASSIGN_ACK:
4173 add_trace("type", NULL, "assign_ack");
4175 case BCHANNEL_REMOVE:
4176 add_trace("type", NULL, "remove");
4178 case BCHANNEL_REMOVE_ACK:
4179 add_trace("type", NULL, "remove_ack");
4182 if (param->bchannel.addr)
4183 add_trace("address", NULL, "%x", param->bchannel.addr);
4189 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4193 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4195 struct lcr_msg *message;
4199 if (!portlist->port_id)
4202 if (!e_connectedmode) {
4203 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4204 message->param.disconnectinfo.cause = cause;
4205 message->param.disconnectinfo.location = location;
4207 SCPY(message->param.disconnectinfo.display, display);
4209 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4211 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4213 SCPY(message->param.notifyinfo.display, display);
4215 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4217 message_put(message);
4218 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);