1 /*****************************************************************************\
3 ** Linux Call Router **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** The EndpointAppPBX implements PBX4Linux **
10 \*****************************************************************************/
15 class EndpointAppPBX *apppbx_first = NULL;
17 int action_timeout(struct lcr_timer *timer, void *instance, int index);
18 int match_timeout(struct lcr_timer *timer, void *instance, int index);
19 int redial_timeout(struct lcr_timer *timer, void *instance, int index);
20 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index);
21 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index);
22 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index);
23 int password_timeout(struct lcr_timer *timer, void *instance, int index);
24 int callback_timeout(struct lcr_timer *timer, void *instance, int index);
27 * EndpointAppPBX constructor
29 EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin)
31 class EndpointAppPBX **apppointer;
33 memset(&e_crypt_handler, 0, sizeof(e_crypt_handler));
34 add_timer(&e_crypt_handler, crypt_handler, this, 0);
35 memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh));
36 add_timer(&e_vbox_refresh, vbox_refresh, this, 0);
37 memset(&e_action_timeout, 0, sizeof(e_action_timeout));
38 add_timer(&e_action_timeout, action_timeout, this, 0);
39 memset(&e_match_timeout, 0, sizeof(e_match_timeout));
40 add_timer(&e_match_timeout, match_timeout, this, 0);
41 memset(&e_redial_timeout, 0, sizeof(e_redial_timeout));
42 add_timer(&e_redial_timeout, redial_timeout, this, 0);
43 memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout));
44 add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0);
45 memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout));
46 add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0);
47 memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout));
48 add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0);
49 memset(&e_callback_timeout, 0, sizeof(e_callback_timeout));
50 add_timer(&e_callback_timeout, callback_timeout, this, 0);
51 memset(&e_password_timeout, 0, sizeof(e_password_timeout));
52 add_timer(&e_password_timeout, password_timeout, this, 0);
55 /* add application to chain */
57 apppointer = &apppbx_first;
59 apppointer = &((*apppointer)->next);
63 memset(&e_ext, 0, sizeof(struct extension));
64 // *************** NOTE: also change value in read_extension() **************
65 e_ext.rights = 4; /* international */
66 e_ext.rx_gain = e_ext.tx_gain = 0;
67 e_state = EPOINT_STATE_IDLE;
68 e_ext.number[0] = '\0';
69 e_extension_interface[0] = '\0';
70 memset(&e_callerinfo, 0, sizeof(struct caller_info));
71 memset(&e_dialinginfo, 0, sizeof(struct dialing_info));
72 memset(&e_connectinfo, 0, sizeof(struct connect_info));
73 memset(&e_redirinfo, 0, sizeof(struct redir_info));
74 memset(&e_capainfo, 0, sizeof(struct capa_info));
77 e_ruleset = ruleset_main;
79 e_rule = e_ruleset->rule_first;
82 e_match_to_action = NULL;
84 e_extdialing = e_dialinginfo.id;
88 // e_join_tone[0] = e_hold_tone[0] = '\0';
89 e_join_pattern /*= e_hold_pattern*/ = 0;
91 e_adminid = 0; // will be set, if call was initiated via admin socket
94 e_cbdialing[0] = '\0';
97 memset(&e_callbackinfo, 0, sizeof(struct caller_info));
103 e_multipoint_cause = 0;
104 e_multipoint_location = 0;
105 e_dialing_queue[0] = '\0';
107 e_crypt_state = CM_ST_NULL;
108 e_crypt_keyengine_busy = 0;
109 e_crypt_info[0] = '\0';
112 e_tx_state = NOTIFY_STATE_ACTIVE;
113 e_rx_state = NOTIFY_STATE_ACTIVE;
114 e_join_cause = e_join_location = 0;
115 /*********************************
116 *********************************
117 ********* ATTENTION *************
118 *********************************
119 *********************************/
120 /* if you add new values, that must be initialized, also check if they must
121 * be initialized when doing callback
127 * EpointAppPBX destructor
129 EndpointAppPBX::~EndpointAppPBX(void)
131 class EndpointAppPBX *temp, **tempp;
133 del_timer(&e_crypt_handler);
134 del_timer(&e_vbox_refresh);
135 del_timer(&e_action_timeout);
136 del_timer(&e_match_timeout);
137 del_timer(&e_redial_timeout);
138 del_timer(&e_powerdial_timeout);
139 del_timer(&e_cfnr_timeout);
140 del_timer(&e_cfnr_call_timeout);
141 del_timer(&e_callback_timeout);
142 del_timer(&e_password_timeout);
146 tempp = &apppbx_first;
155 FATAL("Endpoint not in endpoint's list.\n");
162 * trace header for application
164 void EndpointAppPBX::trace_header(const char *name, int direction)
168 char msgtext[sizeof(_trace.name)];
172 /* init trace with given values */
175 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
179 ea_endpoint->ep_serial,
186 /* set new endpoint state
188 void EndpointAppPBX::new_state(int state)
191 if (e_state != state) {
192 trace_header("NEW STATE", DIRECTION_NONE);
193 add_trace("state", "old", "%s", state_name[e_state]);
194 add_trace("state", "new", "%s", state_name[state]);
202 /* release join and port (as specified)
204 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force)
206 struct port_list *portlist;
207 struct lcr_msg *message;
210 /* message to test call */
211 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
213 /* if a release is pending */
214 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
215 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
216 if (ea_endpoint->ep_join_id) {
217 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
218 message->param.disconnectinfo.cause = joincause;
219 message->param.disconnectinfo.location = joinlocation;
220 message_put(message);
221 ea_endpoint->ep_join_id = 0;
225 if (release != RELEASE_PORT_JOINONLY) {
227 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
232 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
233 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
234 while((portlist = ea_endpoint->ep_portlist)) {
235 if (portlist->port_id) {
236 SPRINT(cause, "cause_%02x", portcause);
237 set_tone(portlist, cause);
238 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
239 message->param.disconnectinfo.cause = portcause;
240 message->param.disconnectinfo.location = portlocation;
241 message->param.disconnectinfo.force = force; // set, if port should release imediately
242 message_put(message);
243 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
245 ea_endpoint->free_portlist(portlist);
248 /* if callback is enabled, call back with the given caller id */
249 if (e_callback_timeout.active) {
250 /* reset some stuff */
251 new_state(EPOINT_STATE_IDLE);
252 memset(&e_connectinfo, 0, sizeof(struct connect_info));
253 memset(&e_redirinfo, 0, sizeof(struct redir_info));
254 e_start = e_stop = 0;
255 e_ruleset = ruleset_main;
257 e_rule = e_ruleset->rule_first;
259 unsched_timer(&e_action_timeout);
260 unsched_timer(&e_match_timeout);
261 unsched_timer(&e_cfnr_timeout);
262 unsched_timer(&e_cfnr_call_timeout);
263 e_match_to_action = NULL;
265 e_extdialing = e_dialinginfo.id;
271 e_multipoint_cause = 0;
272 e_multipoint_location = 0;
273 e_dialing_queue[0] = '\0';
275 e_crypt_state = CM_ST_NULL;
276 e_crypt_keyengine_busy = 0;
277 e_crypt_info[0] = '\0';
281 e_tx_state = NOTIFY_STATE_ACTIVE;
282 e_rx_state = NOTIFY_STATE_ACTIVE;
283 e_join_cause = e_join_location = 0;
285 /* the caller info of the callback user */
286 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
287 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
288 /* create dialing by callerinfo */
289 if (e_ext.number[0] && e_extension_interface[0]) {
290 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
291 /* create callback to the current terminal */
292 SCPY(e_dialinginfo.id, e_ext.number);
293 SCPY(e_dialinginfo.interfaces, e_extension_interface);
294 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
295 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
298 SCPY(e_dialinginfo.id, e_cbto);
300 /* numberrize caller id and use it to dial to the callback */
301 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
303 e_dialinginfo.itype = INFO_ITYPE_ISDN;
304 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
305 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
310 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
311 if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */
312 trigger_work(&ea_endpoint->ep_delete);
318 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
319 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
321 PDEBUG(DEBUG_EPOINT, "id='%s' ntype=%d present=%d screen=%d extension='%s' name='%s'\n", (id)?id:"NULL", (ntype)?*ntype:-1, (present)?*present:-1, (screen)?*screen:-1, (extension)?extension:"NULL", (name)?name:"NULL");
323 /* caller id is not restricted, so we do nothing */
324 if (*present != INFO_PRESENT_RESTRICTED)
327 /* only extensions are restricted */
331 /* if we enabled anonymouse ignore */
332 if (ext->anon_ignore)
335 /* else we remove the caller id */
339 *ntype = INFO_NTYPE_UNKNOWN;
341 // *screen = INFO_SCREEN_USER;
342 // maybe we should not make voip address anonymous
345 // maybe it's no fraud to present extension id
347 // extension[0] = '\0';
352 /* used display message to display callerid as available */
353 char *EndpointAppPBX::apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name)
355 static char display[81];
358 const char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
360 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) id='%s' itype=%d ntype=%d present=%d screen=%d extension='%s' name='%s'\n", ea_endpoint->ep_serial, (id)?id:"NULL", itype, ntype, present, screen, (extension)?extension:"NULL", (name)?name:"NULL");
369 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
371 /* internal extension's caller id */
372 if (extension[0] && e_ext.display_int) {
374 SCAT(display, extension);
377 if (itype == INFO_ITYPE_VBOX)
378 SCAT(display, "(vbox)");
380 SCAT(display, "(int)");
383 /* external caller id */
384 if (!extension[0] && e_ext.display_ext) {
387 if (present == INFO_PRESENT_RESTRICTED)
388 SCAT(display, "anonymous");
390 SCAT(display, "unknown");
397 /* display if callerid is anonymouse but available due anon-ignore */
398 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED) {
400 SCAT(display, "unknown");
403 SCAT(display, " anon");
406 /* display if callerid is anonymouse but available due anon-ignore */
407 if (e_ext.display_fake && screen==INFO_SCREEN_USER && ntype!=INFO_NTYPE_NOTPRESENT) {
410 if (present == INFO_PRESENT_RESTRICTED)
411 SCAT(display, "anonymous");
413 SCAT(display, "unknown");
418 SCAT(display, " fake");
422 if (name[0] && e_ext.display_name) {
423 if (!display[0] && cid[0])
434 * uses the current state to notify activity
436 void EndpointAppPBX::notify_active(void)
438 struct port_list *portlist = ea_endpoint->ep_portlist;
439 struct lcr_msg *message;
443 case NOTIFY_STATE_ACTIVE:
444 /* we are already active, so we don't do anything */
447 case NOTIFY_STATE_SUSPEND:
448 notify = INFO_NOTIFY_USER_RESUMED;
450 set_tone(portlist, NULL);
451 portlist = portlist->next;
453 portlist = ea_endpoint->ep_portlist;
456 case NOTIFY_STATE_HOLD:
457 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
459 set_tone(portlist, NULL);
460 portlist = portlist->next;
462 portlist = ea_endpoint->ep_portlist;
465 case NOTIFY_STATE_CONFERENCE:
466 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
468 set_tone(portlist, NULL);
469 portlist = portlist->next;
471 portlist = ea_endpoint->ep_portlist;
475 PERROR("unknown e_tx_state = %d\n", e_tx_state);
480 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
481 message->param.notifyinfo.notify = notify;
482 message_put(message);
483 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
484 portlist = portlist->next;
490 * keypad functions during call. one example to use this is to put a call on hold or start a conference
492 void EndpointAppPBX::keypad_function(char digit)
495 /* we must be in a call, in order to send messages to the call */
496 if (e_ext.number[0] == '\0') {
497 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
502 /* join conference */
504 if (ea_endpoint->ep_join_id == 0) {
505 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
508 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
514 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
518 /* crypt key-exchange */
520 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
526 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
531 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
536 /* set tone pattern for port */
537 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
539 struct lcr_msg *message;
544 /* store for suspended processes */
548 if (e_join_pattern /* pattern are provided */
549 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
550 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
551 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
552 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
553 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
554 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
555 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
556 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
557 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
558 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
559 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
560 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
565 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
566 SCPY(message->param.tone.dir, e_ext.tones_dir);
567 SCPY(message->param.tone.name, tone);
568 message_put(message);
569 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
571 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
578 * hunts an mISDNport that is available for an outgoing call
579 * if no ifname was given, any interface that is not an extension
582 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
584 struct interface *interface;
585 struct interface_port *ifport, *ifport_start;
586 struct select_channel *selchannel;
587 struct mISDNport *mISDNport;
589 int there_is_an_external = 0;
591 interface = interface_first;
593 /* first find the given interface or, if not given, one with no extension */
596 if (!there_is_an_external && !(ifname && ifname[0])) {
597 trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
598 add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
604 /* check for given interface */
605 if (ifname && ifname[0]) {
606 if (!strcasecmp(interface->name, ifname)) {
607 /* found explicit interface */
608 trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
609 add_trace("interface", NULL, "%s", ifname);
615 if (interface->external) {
616 there_is_an_external = 1;
617 /* found non extension */
618 trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
619 add_trace("interface", NULL, "%s", interface->name);
625 interface = interface->next;
629 /* see if interface has ports */
630 if (!interface->ifport) {
632 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
633 add_trace("interface", NULL, "%s", interface->name);
635 interface = interface->next;
639 /* select port by algorithm */
640 ifport_start = interface->ifport;
642 if (interface->hunt == HUNT_ROUNDROBIN) {
643 while(ifport_start->next && index<interface->hunt_next) {
644 ifport_start = ifport_start->next;
647 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
648 add_trace("port", NULL, "%d", ifport_start->portnum);
649 add_trace("position", NULL, "%d", index);
654 ifport = ifport_start;
657 /* see if port is available */
658 if (!ifport->mISDNport) {
659 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
660 add_trace("port", NULL, "%d", ifport->portnum);
661 add_trace("position", NULL, "%d", index);
665 mISDNport = ifport->mISDNport;
667 /* see if port is administratively blocked */
669 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
670 add_trace("port", NULL, "%d", ifport->portnum);
671 add_trace("position", NULL, "%d", index);
676 /* see if link is up on PTP*/
677 if (mISDNport->l2hold && mISDNport->l2link<1) {
678 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
679 add_trace("port", NULL, "%d", ifport->portnum);
680 add_trace("position", NULL, "%d", index);
685 /* check for channel form selection list */
688 if (mISDNport->ss5) {
690 port = ss5_hunt_line(mISDNport);
692 *channel = port->p_m_b_channel;
693 trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
694 add_trace("port", NULL, "%d", ifport->portnum);
695 add_trace("position", NULL, "%d", index);
696 add_trace("channel", NULL, "%d", *channel);
702 selchannel = ifport->out_channel;
704 switch(selchannel->channel) {
705 case CHANNEL_FREE: /* free channel */
706 if (mISDNport->b_reserved >= mISDNport->b_num)
707 break; /* all channel in use or reserverd */
710 while(i < mISDNport->b_num) {
711 if (mISDNport->b_port[i] == NULL) {
712 *channel = i+1+(i>=15);
713 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
714 add_trace("port", NULL, "%d", ifport->portnum);
715 add_trace("position", NULL, "%d", index);
716 add_trace("channel", NULL, "%d", *channel);
724 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
725 add_trace("port", NULL, "%d", ifport->portnum);
726 add_trace("position", NULL, "%d", index);
730 case CHANNEL_ANY: /* don't ask for channel */
731 if (mISDNport->b_reserved >= mISDNport->b_num) {
732 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
733 add_trace("port", NULL, "%d", ifport->portnum);
734 add_trace("position", NULL, "%d", index);
735 add_trace("total", NULL, "%d", mISDNport->b_num);
736 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
738 break; /* all channel in use or reserverd */
740 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
741 add_trace("port", NULL, "%d", ifport->portnum);
742 add_trace("position", NULL, "%d", index);
744 *channel = CHANNEL_ANY;
747 case CHANNEL_NO: /* call waiting */
748 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
749 add_trace("port", NULL, "%d", ifport->portnum);
750 add_trace("position", NULL, "%d", index);
752 *channel = CHANNEL_NO;
756 if (selchannel->channel<1 || selchannel->channel==16) {
757 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
758 add_trace("port", NULL, "%d", ifport->portnum);
759 add_trace("position", NULL, "%d", index);
760 add_trace("channel", NULL, "%d", selchannel->channel);
762 break; /* invalid channels */
764 i = selchannel->channel-1-(selchannel->channel>=17);
765 if (i >= mISDNport->b_num) {
766 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
767 add_trace("port", NULL, "%d", ifport->portnum);
768 add_trace("position", NULL, "%d", index);
769 add_trace("channel", NULL, "%d", selchannel->channel);
770 add_trace("channels", NULL, "%d", mISDNport->b_num);
772 break; /* channel not in port */
774 if (mISDNport->b_port[i] == NULL) {
775 *channel = selchannel->channel;
776 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
777 add_trace("port", NULL, "%d", ifport->portnum);
778 add_trace("position", NULL, "%d", index);
779 add_trace("channel", NULL, "%d", *channel);
786 break; /* found channel */
787 selchannel = selchannel->next;
791 /* if channel was found, return mISDNport and channel */
793 /* setting next port to start next time */
794 if (interface->hunt == HUNT_ROUNDROBIN) {
798 interface->hunt_next = index;
804 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
805 add_trace("port", NULL, "%d", ifport->portnum);
806 add_trace("position", NULL, "%d", index);
810 /* go next port, until all ports are checked */
812 ifport = ifport->next;
815 ifport = interface->ifport;
817 if (ifport != ifport_start)
821 interface = interface->next;
825 return(NULL); /* no port found */
828 /* outgoing setup to port(s)
829 * ports will be created and a setup is sent if everything is ok. otherwhise
830 * the endpoint is destroyed.
832 void EndpointAppPBX::out_setup(void)
834 struct dialing_info dialinginfo;
836 struct port_list *portlist;
837 struct lcr_msg *message;
839 int cause = CAUSE_RESSOURCEUNAVAIL;
842 struct mISDNport *mISDNport;
845 class EndpointAppPBX *atemp;
846 // char allowed_ports[256];
848 char ifname[sizeof(e_ext.interfaces)],
850 struct port_settings port_settings;
853 int mode = B_MODE_TRANSPARENT;
855 /* set bchannel mode */
856 mode = e_capainfo.source_mode;
858 /* create settings for creating port */
859 memset(&port_settings, 0, sizeof(port_settings));
861 SCPY(port_settings.tones_dir, e_ext.tones_dir);
863 SCPY(port_settings.tones_dir, options.tones_dir);
864 port_settings.no_seconds = e_ext.no_seconds;
866 /* NOTE: currently the try_card feature is not supported. it should be used later to try another card, if the outgoing call fails on one port */
868 /* check what dialinginfo.itype we got */
869 switch(e_dialinginfo.itype) {
870 /* *********************** call to extension or vbox */
871 case INFO_ITYPE_ISDN_EXTENSION:
872 /* check if we deny incoming calls when we use an extension */
873 if (e_ext.noknocking) {
874 atemp = apppbx_first;
877 if (!strcmp(atemp->e_ext.number, e_ext.number))
882 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
883 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
884 return; /* must exit here */
887 /* FALL THROUGH !!!! */
888 case INFO_ITYPE_VBOX:
889 /* get dialed extension's info */
890 // SCPY(exten, e_dialinginfo.id);
891 // if (strchr(exten, ','))
892 // *strchr(exten, ',') = '\0';
893 // if (!read_extension(&e_ext, exten))
894 if (!read_extension(&e_ext, e_dialinginfo.id)) {
895 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
896 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
897 return; /* must exit here */
899 e_dialinginfo.sending_complete = 1;
901 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
902 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
907 /* string from unconditional call forward (cfu) */
910 /* present to forwarded party */
911 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
912 e_callerinfo.present = INFO_PRESENT_ALLOWED;
914 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
918 /* string from busy call forward (cfb) */
921 class EndpointAppPBX *checkapp = apppbx_first;
923 if (checkapp != this) { /* any other endpoint except our own */
924 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
925 /* present to forwarded party */
926 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
927 e_callerinfo.present = INFO_PRESENT_ALLOWED;
929 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
933 checkapp = checkapp->next;
937 /* string from no-response call forward (cfnr) */
940 /* when cfnr is done, out_setup() will setup the call */
941 if (e_cfnr_call_timeout.active) {
942 /* present to forwarded party */
943 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
944 e_callerinfo.present = INFO_PRESENT_ALLOWED;
948 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
949 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
950 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
951 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) setting time for call-forward-busy to %s with delay %ld.\n", ea_endpoint->ep_serial, e_ext.cfnr, e_ext.cfnr_delay);
955 /* call to all internal interfaces */
956 p = e_ext.interfaces;
957 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
960 while(*p!=',' && *p!='\0')
965 /* found interface */
966 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
967 /* hunt for mISDNport and create Port */
968 mISDNport = hunt_port(ifname, &channel);
970 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
971 add_trace("interface", NULL, "%s", ifname);
975 /* creating INTERNAL port */
976 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
979 port = ss5_hunt_line(mISDNport);
983 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
986 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
991 FATAL("No memory for Port instance\n");
992 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
993 memset(&dialinginfo, 0, sizeof(dialinginfo));
994 SCPY(dialinginfo.id, e_dialinginfo.id);
995 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
996 dialinginfo.ntype = e_dialinginfo.ntype;
997 /* create port_list relation */
998 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1000 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1002 goto check_anycall_intern;
1004 /* directory.list */
1005 if (e_callerinfo.id[0] && e_ext.display_name) {
1006 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1008 SCPY(e_callerinfo.name, dirname);
1010 // dss1 = (class Pdss1 *)port;
1012 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1013 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1014 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1015 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1016 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1017 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1018 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1019 //terminal if (e_dialinginfo.id)
1020 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1021 /* handle restricted caller ids */
1022 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1023 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1024 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1025 /* display callerid if desired for extension */
1026 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
1027 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1028 /* use cnip, if enabld */
1029 // if (!e_ext.centrex)
1030 // message->param.setup.callerinfo.name[0] = '\0';
1031 /* screen clip if prefix is required */
1032 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1033 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1034 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1035 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1037 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1038 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1039 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1040 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1042 /* use internal caller id */
1043 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1044 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1045 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1046 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1048 message_put(message);
1049 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1053 /* string from parallel call forward (cfp) */
1056 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1057 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1058 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1062 vbox_only: /* entry point for answering machine only */
1063 cfu_only: /* entry point for cfu */
1064 cfb_only: /* entry point for cfb */
1065 cfnr_only: /* entry point for cfnr */
1066 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1070 /* only if vbox should be dialed, and terminal is given */
1071 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1072 /* go to the end of p */
1075 /* answering vbox call */
1076 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1078 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1079 FATAL("No memory for VBOX Port instance\n");
1080 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1081 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1084 while(*p!=',' && *p!='\0')
1089 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1090 /* hunt for mISDNport and create Port */
1091 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1093 /* creating EXTERNAL port*/
1094 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1097 port = ss5_hunt_line(mISDNport);
1100 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1102 FATAL("No memory for Port instance\n");
1103 earlyb = mISDNport->earlyb;
1106 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1107 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1112 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1113 goto check_anycall_intern;
1115 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1116 memset(&dialinginfo, 0, sizeof(dialinginfo));
1117 SCPY(dialinginfo.id, cfp);
1118 dialinginfo.itype = INFO_ITYPE_ISDN;
1119 dialinginfo.ntype = e_dialinginfo.ntype;
1120 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1122 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1124 goto check_anycall_intern;
1126 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1127 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1128 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1129 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1130 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1131 /* if clip is hidden */
1132 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1133 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1134 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1135 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1136 message->param.setup.callerinfo.present = e_ext.callerid_present;
1137 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1139 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1140 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1141 //terminal if (e_dialinginfo.id)
1142 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1143 /* handle restricted caller ids */
1144 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1145 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1146 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1147 /* display callerid if desired for extension */
1148 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
1149 message_put(message);
1150 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1154 check_anycall_intern:
1155 /* now we have all ports created */
1157 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1159 if (!ea_endpoint->ep_join_id)
1161 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1162 return; /* must exit here */
1166 /* *********************** external call */
1168 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1169 /* call to extenal interfaces */
1170 if (e_dialinginfo.keypad[0])
1171 p = e_dialinginfo.keypad;
1173 p = e_dialinginfo.id;
1176 while(*p!=',' && *p!='\0')
1177 SCCAT(number, *p++);
1181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to number '%s' interface '%s'\n", ea_endpoint->ep_serial, number, e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1182 /* hunt for mISDNport and create Port */
1183 /* hunt for mISDNport and create Port */
1184 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1186 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1187 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1189 goto check_anycall_extern;
1191 /* creating EXTERNAL port*/
1192 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1195 port = ss5_hunt_line(mISDNport);
1198 if (!mISDNport->gsm)
1199 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1202 port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
1207 FATAL("No memory for Port instance\n");
1208 earlyb = mISDNport->earlyb;
1209 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1210 memset(&dialinginfo, 0, sizeof(dialinginfo));
1211 if (e_dialinginfo.keypad[0])
1212 SCPY(dialinginfo.keypad, number);
1214 SCPY(dialinginfo.id, number);
1215 dialinginfo.itype = INFO_ITYPE_ISDN;
1216 dialinginfo.ntype = e_dialinginfo.ntype;
1217 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1218 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1220 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1222 goto check_anycall_extern;
1224 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1225 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1226 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1227 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1228 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1229 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1230 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1231 //terminal if (e_dialinginfo.id)
1232 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1233 /* handle restricted caller ids */
1234 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1235 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id2, &message->param.setup.callerinfo.ntype2, &message->param.setup.callerinfo.present2, &message->param.setup.callerinfo.screen2, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1236 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1237 /* display callerid if desired for extension */
1238 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
1239 message_put(message);
1240 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1244 check_anycall_extern:
1245 /* now we have all ports created */
1247 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1249 if (!ea_endpoint->ep_join_id)
1251 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1252 return; /* must exit here */
1259 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1261 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1263 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1266 unsched_timer(&ea->e_redial_timeout);
1267 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1268 ea->e_multipoint_cause = 0;
1269 ea->e_multipoint_location = 0;
1270 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1271 ea->e_join_pattern = 0;
1272 ea->process_dialing(1);
1273 /* we must exit, because our endpoint might be gone */
1278 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1280 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1282 if (!ea->e_action) {
1283 unsched_timer(&ea->e_redial_timeout);
1284 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1285 ea->process_dialing(0);
1286 /* we must exit, because our endpoint might be gone */
1292 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1294 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1296 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1298 ea->new_state(EPOINT_STATE_OUT_SETUP);
1299 /* call special setup routine */
1305 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1307 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1309 /* leave power dialing on */
1310 ea->e_powerdial_on = 1;
1311 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1314 ea->e_ruleset = ruleset_main;
1316 ea->e_rule = ea->e_ruleset->rule_first;
1317 ea->e_action = NULL;
1318 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1319 ea->process_dialing(0);
1324 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1326 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1327 struct port_list *portlist;
1328 struct lcr_msg *message;
1330 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1332 /* release all ports */
1333 while((portlist = ea->ea_endpoint->ep_portlist)) {
1334 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1335 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1336 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1337 message_put(message);
1338 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1339 ea->ea_endpoint->free_portlist(portlist);
1342 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1343 message->param.audiopath = 0;
1344 message_put(message);
1345 /* indicate no patterns */
1346 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1347 message_put(message);
1348 /* set setup state, since we have no response from the new join */
1349 ea->new_state(EPOINT_STATE_OUT_SETUP);
1354 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1356 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1358 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea->ea_endpoint->ep_serial, ea->e_ext.cfnr);
1364 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1366 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1368 if (ea->e_state == EPOINT_STATE_IDLE) {
1369 /* epoint is idle, check callback */
1370 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1371 ea->new_state(EPOINT_STATE_OUT_SETUP);
1378 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1380 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1382 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1383 struct port_list *portlist;
1385 ea->e_ruleset = ruleset_main;
1387 ea->e_rule = ea->e_ruleset->rule_first;
1388 ea->e_action = NULL;
1389 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1390 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1392 ea->e_connectedmode = 0;
1394 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1395 portlist = ea->ea_endpoint->ep_portlist;
1397 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1398 ea->set_tone(portlist, "cause_10");
1405 /* doing a hookflash */
1406 void EndpointAppPBX::hookflash(void)
1411 /* be sure that we are active */
1413 e_tx_state = NOTIFY_STATE_ACTIVE;
1415 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1417 if (ea_endpoint->ep_use > 1) {
1418 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1421 /* dialtone after pressing the hash key */
1422 process_hangup(e_join_cause, e_join_location);
1423 e_multipoint_cause = 0;
1424 e_multipoint_location = 0;
1425 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1427 port->set_echotest(0);
1429 if (ea_endpoint->ep_join_id) {
1430 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1432 e_ruleset = ruleset_main;
1434 e_rule = e_ruleset->rule_first;
1436 new_state(EPOINT_STATE_IN_OVERLAP);
1437 e_connectedmode = 1;
1438 SCPY(e_dialinginfo.id, e_ext.prefix);
1439 e_extdialing = e_dialinginfo.id;
1441 if (e_dialinginfo.id[0]) {
1442 set_tone(ea_endpoint->ep_portlist, "dialing");
1445 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1453 /* messages from port
1455 /* port MESSAGE_SETUP */
1456 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1458 struct lcr_msg *message;
1460 int writeext; /* flags need to write extension after modification */
1462 struct interface *interface;
1464 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1466 portlist->port_type = param->setup.port_type;
1467 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1468 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1469 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1470 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1472 /* convert (inter-)national number type */
1473 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1474 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1476 // e_dtmf = param->setup.dtmf;
1477 /* screen incoming caller id */
1478 interface = interface_first;
1480 if (!strcmp(e_callerinfo.interface, interface->name)) {
1483 interface = interface->next;
1486 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1487 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, interface);
1490 /* process extension */
1491 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1492 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1493 /* port makes call from extension */
1494 SCPY(e_callerinfo.extension, e_callerinfo.id);
1495 SCPY(e_ext.number, e_callerinfo.extension);
1496 SCPY(e_extension_interface, e_callerinfo.interface);
1498 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1501 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1502 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1504 /* get extension's info about caller */
1505 if (!read_extension(&e_ext, e_ext.number)) {
1506 /* extension doesn't exist */
1507 trace_header("EXTENSION (not created)", DIRECTION_IN);
1508 add_trace("extension", NULL, "%s", e_ext.number);
1510 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1511 new_state(EPOINT_STATE_OUT_DISCONNECT);
1512 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1513 e_ext.number[0] = '\0'; /* no terminal */
1518 /* put prefix (next) in front of e_dialinginfo.id */
1519 if (e_ext.next[0]) {
1520 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1521 SCPY(e_dialinginfo.id, buffer);
1522 e_ext.next[0] = '\0';
1524 } else if (e_ext.prefix[0]) {
1525 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1526 SCPY(e_dialinginfo.id, buffer);
1529 /* screen caller id by extension's config */
1530 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1532 SCPY(e_callerinfo.name, e_ext.name);
1533 /* use caller id (or if exist: id_next_call) for this call */
1534 if (e_ext.id_next_call_present >= 0) {
1535 SCPY(e_callerinfo.id, e_ext.id_next_call);
1536 /* if we restrict the pesentation */
1537 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1538 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1539 else e_callerinfo.present = e_ext.id_next_call_present;
1540 e_callerinfo.ntype = e_ext.id_next_call_type;
1541 e_ext.id_next_call_present = -1;
1544 SCPY(e_callerinfo.id, e_ext.callerid);
1545 /* if we restrict the pesentation */
1546 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1547 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1548 else e_callerinfo.present = e_ext.callerid_present;
1549 e_callerinfo.ntype = e_ext.callerid_type;
1551 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1553 /* extension is written */
1555 write_extension(&e_ext, e_ext.number);
1557 /* set volume of rx and tx */
1558 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1559 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1560 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1561 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1562 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1563 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1564 message_put(message);
1567 /* start recording if enabled */
1568 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1569 /* check if we are a terminal */
1570 if (e_ext.number[0] == '\0')
1571 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1573 port = find_port_id(portlist->port_id);
1575 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1579 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1580 /* no terminal identification */
1581 e_ext.number[0] = '\0';
1582 e_extension_interface[0] = '\0';
1583 memset(&e_ext, 0, sizeof(e_ext));
1584 e_ext.rights = 4; /* right to dial internat */
1588 e_ruleset = ruleset_main;
1590 e_rule = e_ruleset->rule_first;
1592 e_extdialing = e_dialinginfo.id;
1593 new_state(EPOINT_STATE_IN_SETUP);
1594 if (e_dialinginfo.id[0]) {
1595 set_tone(portlist, "dialing");
1597 if (e_ext.number[0])
1598 set_tone(portlist, "dialpbx");
1600 set_tone(portlist, "dialtone");
1603 if (e_state == EPOINT_STATE_IN_SETUP) {
1604 /* request MORE info, if not already at higher state */
1605 new_state(EPOINT_STATE_IN_OVERLAP);
1606 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1607 message_put(message);
1608 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1612 /* port MESSAGE_INFORMATION */
1613 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1615 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1617 /* ignore information message without digit information */
1618 if (!param->information.id[0])
1623 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1625 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1630 /* if vbox_play is done, the information are just used as they come */
1632 if (e_action->index == ACTION_VBOX_PLAY) {
1633 /* concat dialing string */
1634 SCAT(e_dialinginfo.id, param->information.id);
1639 /* keypad when disconnect but in connected mode */
1640 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1641 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1642 /* processing keypad function */
1643 if (param->information.id[0] == '0') {
1649 /* keypad when connected */
1650 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1651 if (e_ext.keypad || e_enablekeypad) {
1652 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1653 /* processing keypad function */
1654 if (param->information.id[0] == '0') {
1657 if (param->information.id[0])
1658 keypad_function(param->information.id[0]);
1660 if (e_ext.number[0])
1661 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1663 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1668 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1669 if (e_ext.number[0])
1670 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1672 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1676 if (!param->information.id[0])
1678 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1679 set_tone(portlist, "dialing");
1682 if (e_action->index==ACTION_OUTDIAL
1683 || e_action->index==ACTION_EXTERNAL
1684 || e_action->index==ACTION_REMOTE) {
1686 set_tone(portlist, "dialing");
1687 else if (!e_extdialing[0])
1688 set_tone(portlist, "dialing");
1690 /* concat dialing string */
1691 SCAT(e_dialinginfo.id, param->information.id);
1695 /* port MESSAGE_DTMF */
1696 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1702 /* only if dtmf detection is enabled */
1704 trace_header("DTMF (disabled)", DIRECTION_IN);
1708 trace_header("DTMF", DIRECTION_IN);
1709 add_trace("digit", NULL, "%c", param->dtmf);
1713 NOTE: vbox is now handled due to overlap state
1714 /* if vbox_play is done, the dtmf digits are just used as they come */
1716 if (e_action->index == ACTION_VBOX_PLAY) {
1717 /* concat dialing string */
1718 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1719 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1720 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1723 /* continue to process *X# sequences */
1727 /* check for *X# sequence */
1728 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1729 if (e_dtmf_time+3 < now) {
1730 /* the last digit was too far in the past to be a sequence */
1731 if (param->dtmf == '*')
1732 /* only start is allowed in the sequence */
1737 /* we have a sequence of digits, see what we got */
1738 if (param->dtmf == '*')
1740 else if (param->dtmf>='0' && param->dtmf<='9') {
1741 /* we need to have a star before we receive the digit of the sequence */
1742 if (e_dtmf_last == '*')
1743 e_dtmf_last = param->dtmf;
1744 } else if (param->dtmf == '#') {
1746 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1747 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1748 if (e_dtmf_last == '0') {
1752 /* processing keypad function */
1754 keypad_function(e_dtmf_last);
1760 /* set last time of dtmf */
1765 /* check for ## hookflash during dialing */
1767 if (e_action->index==ACTION_PASSWORD
1768 || e_action->index==ACTION_PASSWORD_WRITE)
1770 if (param->dtmf=='#') { /* current digit is '#' */
1771 if (e_state==EPOINT_STATE_IN_DISCONNECT
1772 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1786 /* dialing using dtmf digit */
1787 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1788 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1789 set_tone(portlist, "dialing");
1791 /* concat dialing string */
1792 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1793 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1794 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1800 /* port MESSAGE_CRYPT */
1801 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1803 /* send crypt response to cryptman */
1804 if (param->crypt.type == CR_MESSAGE_IND)
1805 cryptman_msg2man(param->crypt.data, param->crypt.len);
1807 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1810 /* port MESSAGE_OVERLAP */
1811 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1813 struct lcr_msg *message;
1815 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1817 /* signal to call tool */
1818 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1820 if (e_dialing_queue[0] && portlist) {
1821 /* send what we have not dialed yet, because we had no setup complete */
1822 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1823 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1824 SCPY(message->param.information.id, e_dialing_queue);
1825 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1826 message_put(message);
1827 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1828 e_dialing_queue[0] = '\0';
1830 /* check if pattern is available */
1831 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1832 /* indicate patterns */
1833 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1834 message_put(message);
1836 /* connect audio, if not already */
1837 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1838 message->param.audiopath = 1;
1839 message_put(message);
1841 /* indicate no patterns */
1842 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1843 message_put(message);
1845 /* disconnect audio, if not already */
1846 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1847 message->param.audiopath = 0;
1848 message_put(message);
1850 new_state(EPOINT_STATE_OUT_OVERLAP);
1851 /* if we are in a join */
1852 if (ea_endpoint->ep_join_id) {
1853 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1854 memcpy(&message->param, param, sizeof(union parameter));
1855 message_put(message);
1859 /* port MESSAGE_PROCEEDING */
1860 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1862 struct lcr_msg *message;
1864 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1866 /* signal to call tool */
1867 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1869 e_state = EPOINT_STATE_OUT_PROCEEDING;
1870 /* check if pattern is availatle */
1871 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1872 /* indicate patterns */
1873 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1874 message_put(message);
1876 /* connect audio, if not already */
1877 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1878 message->param.audiopath = 1;
1879 message_put(message);
1881 /* indicate no patterns */
1882 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1883 message_put(message);
1885 /* disconnect audio, if not already */
1886 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1887 message->param.audiopath = 0;
1888 message_put(message);
1890 /* if we are in a call */
1891 if (ea_endpoint->ep_join_id) {
1892 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1893 memcpy(&message->param, param, sizeof(union parameter));
1894 message_put(message);
1898 /* port MESSAGE_ALERTING */
1899 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1901 struct lcr_msg *message;
1903 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1905 /* signal to call tool */
1906 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1909 // set_tone(portlist, "hold");
1911 new_state(EPOINT_STATE_OUT_ALERTING);
1912 /* check if pattern is available */
1913 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
1914 /* indicate patterns */
1915 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1916 message_put(message);
1918 /* connect audio, if not already */
1919 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1920 message->param.audiopath = 1;
1921 message_put(message);
1923 /* indicate no patterns */
1924 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1925 message_put(message);
1927 /* disconnect audio, if not already */
1928 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1929 message->param.audiopath = 0;
1930 message_put(message);
1932 /* if we are in a call */
1933 if (ea_endpoint->ep_join_id) {
1934 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1935 memcpy(&message->param, param, sizeof(union parameter));
1936 message_put(message);
1940 /* port MESSAGE_CONNECT */
1941 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1943 struct lcr_msg *message;
1945 unsigned int port_id = portlist->port_id;
1946 struct port_list *tportlist;
1948 struct interface *interface;
1951 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1953 /* signal to call tool */
1954 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
1956 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
1957 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
1958 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
1959 tportlist = ea_endpoint->ep_portlist;
1960 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
1961 tportlist = tportlist->next;
1962 if (tportlist->port_id == port_id)
1963 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
1964 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1965 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
1966 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1967 message_put(message);
1968 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
1969 ea_endpoint->free_portlist(tportlist);
1971 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
1976 /* screen incoming connected id */
1977 interface = interface_first;
1979 if (!strcmp(e_connectinfo.interface, interface->name)) {
1982 interface = interface->next;
1985 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
1987 /* screen connected name */
1989 SCPY(e_connectinfo.name, e_ext.name);
1991 /* add internal id to colp */
1992 SCPY(e_connectinfo.extension, e_ext.number);
1994 /* we store the connected port number */
1995 SCPY(e_extension_interface, e_connectinfo.interface);
1997 /* for internal and am calls, we get the extension's id */
1998 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
1999 SCPY(e_connectinfo.id, e_ext.callerid);
2000 SCPY(e_connectinfo.extension, e_ext.number);
2001 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2002 e_connectinfo.ntype = e_ext.callerid_type;
2003 e_connectinfo.present = e_ext.callerid_present;
2005 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2006 e_connectinfo.itype = INFO_ITYPE_VBOX;
2007 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2010 new_state(EPOINT_STATE_CONNECT);
2012 /* set volume of rx and tx */
2013 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2014 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2015 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2016 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2017 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2018 message_put(message);
2021 unsched_timer(&e_cfnr_timeout);
2022 unsched_timer(&e_cfnr_call_timeout);
2023 if (e_ext.number[0])
2024 e_dtmf = 1; /* allow dtmf */
2027 /* other calls with no caller id (or not available for the extension) and force colp */
2028 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2029 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2030 if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT || portlist->port_type==PORT_TYPE_GSM_OUT) { /* external extension answered */
2031 port = find_port_id(portlist->port_id);
2033 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2034 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2039 /* send connect to join */
2040 if (ea_endpoint->ep_join_id) {
2041 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2042 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2043 message_put(message);
2045 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2046 message->param.audiopath = 1;
2047 message_put(message);
2048 } else if (!e_adminid) {
2050 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2051 SCPY(e_ext.number, e_cbcaller);
2052 new_state(EPOINT_STATE_IN_OVERLAP);
2053 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2055 /* get extension's info about terminal */
2056 if (!read_extension(&e_ext, e_ext.number)) {
2057 /* extension doesn't exist */
2058 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2059 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2060 new_state(EPOINT_STATE_OUT_DISCONNECT);
2061 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2065 /* put prefix in front of e_cbdialing */
2066 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2067 SCPY(e_dialinginfo.id, buffer);
2068 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2069 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2071 /* use caller id (or if exist: id_next_call) for this call */
2072 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2073 SCPY(e_callerinfo.extension, e_ext.number);
2074 if (e_ext.id_next_call_present >= 0) {
2075 SCPY(e_callerinfo.id, e_ext.id_next_call);
2076 e_callerinfo.present = e_ext.id_next_call_present;
2077 e_callerinfo.ntype = e_ext.id_next_call_type;
2078 e_ext.id_next_call_present = -1;
2079 /* extension is written */
2080 write_extension(&e_ext, e_ext.number);
2082 SCPY(e_callerinfo.id, e_ext.callerid);
2083 e_callerinfo.present = e_ext.callerid_present;
2084 e_callerinfo.ntype = e_ext.callerid_type;
2086 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2088 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2091 /* check if caller id is NOT authenticated */
2092 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2093 /* make call state to enter password */
2094 new_state(EPOINT_STATE_IN_OVERLAP);
2095 e_action = &action_password_write;
2096 unsched_timer(&e_match_timeout);
2097 e_match_to_action = NULL;
2098 e_dialinginfo.id[0] = '\0';
2099 e_extdialing = strchr(e_dialinginfo.id, '\0');
2100 schedule_timer(&e_password_timeout, 20, 0);
2103 /* incoming call (callback) */
2104 e_ruleset = ruleset_main;
2106 e_rule = e_ruleset->rule_first;
2108 e_extdialing = e_dialinginfo.id;
2109 if (e_dialinginfo.id[0]) {
2110 set_tone(portlist, "dialing");
2113 set_tone(portlist, "dialpbx");
2116 } else { /* testcall */
2117 set_tone(portlist, "hold");
2120 /* start recording if enabled, not when answering machine answers */
2121 if (param->connectinfo.itype!=INFO_ITYPE_VBOX && e_ext.number[0] && e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
2122 /* check if we are a terminal */
2123 if (e_ext.number[0] == '\0')
2124 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2126 port = find_port_id(portlist->port_id);
2128 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2133 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2134 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2136 struct lcr_msg *message;
2138 unsigned int port_id = portlist->port_id;
2142 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2144 /* signal to call tool */
2145 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2147 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2148 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2149 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2154 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current multipoint cause %d location %d, received cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2155 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2156 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2158 /* check if we have more than one portlist relation and we just ignore the disconnect */
2159 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2160 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2161 portlist = ea_endpoint->ep_portlist;
2163 if (portlist->port_id == port_id)
2165 portlist = portlist->next;
2168 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2169 if (message_type != MESSAGE_RELEASE) {
2170 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2171 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2172 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2173 message_put(message);
2174 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2176 ea_endpoint->free_portlist(portlist);
2177 return; /* one relation removed */
2179 if (e_state == EPOINT_STATE_CONNECT) {
2180 /* use cause from port after connect */
2181 cause = param->disconnectinfo.cause;
2182 location = param->disconnectinfo.location;
2184 /* use multipoint cause if no connect yet */
2185 if (e_multipoint_cause) {
2186 cause = e_multipoint_cause;
2187 location = e_multipoint_location;
2189 cause = CAUSE_NOUSER;
2190 location = LOCATION_PRIVATE_LOCAL;
2194 unsched_timer(&e_cfnr_timeout);
2195 unsched_timer(&e_cfnr_call_timeout);
2197 /* process hangup */
2198 process_hangup(e_join_cause, e_join_location);
2199 e_multipoint_cause = 0;
2200 e_multipoint_location = 0;
2202 if (message_type == MESSAGE_DISCONNECT) {
2203 /* tone to disconnected end */
2204 SPRINT(buffer, "cause_%02x", cause);
2205 if (ea_endpoint->ep_portlist)
2206 set_tone(ea_endpoint->ep_portlist, buffer);
2208 new_state(EPOINT_STATE_IN_DISCONNECT);
2211 if (ea_endpoint->ep_join_id) {
2212 int haspatterns = 0;
2213 /* check if pattern is available */
2214 if (ea_endpoint->ep_portlist)
2215 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2216 if (joinpbx_countrelations(ea_endpoint->ep_join_id)==2 // we must count relations, in order not to disturb the conference ; NOTE: asterisk always counts two, since it is a point to point call
2217 && message_type != MESSAGE_RELEASE) // if we release, we are done
2220 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2221 /* indicate patterns */
2222 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2223 message_put(message);
2224 /* connect audio, if not already */
2225 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2226 message->param.audiopath = 1;
2227 message_put(message);
2228 /* send disconnect */
2229 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2230 memcpy(&message->param, param, sizeof(union parameter));
2231 message_put(message);
2232 /* disable encryption if disconnected */
2233 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2235 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2238 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2241 if (message_type == MESSAGE_RELEASE)
2242 ea_endpoint->free_portlist(portlist);
2243 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2244 return; /* must exit here */
2247 /* port MESSAGE_TIMEOUT */
2248 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2252 trace_header("TIMEOUT", DIRECTION_IN);
2253 message_type = MESSAGE_DISCONNECT;
2254 switch (param->state) {
2255 case PORT_STATE_OUT_SETUP:
2256 case PORT_STATE_OUT_OVERLAP:
2257 add_trace("state", NULL, "outgoing setup/dialing");
2259 /* no user responding */
2260 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2261 return; /* must exit here */
2263 case PORT_STATE_IN_SETUP:
2264 case PORT_STATE_IN_OVERLAP:
2265 add_trace("state", NULL, "incoming setup/dialing");
2266 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2267 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2270 case PORT_STATE_OUT_PROCEEDING:
2271 add_trace("state", NULL, "outgoing proceeding");
2273 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2274 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2275 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2276 return; /* must exit here */
2278 case PORT_STATE_IN_PROCEEDING:
2279 add_trace("state", NULL, "incoming proceeding");
2280 param->disconnectinfo.cause = CAUSE_NOUSER;
2281 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2284 case PORT_STATE_OUT_ALERTING:
2285 add_trace("state", NULL, "outgoing alerting");
2287 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2288 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2289 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2290 return; /* must exit here */
2292 case PORT_STATE_CONNECT:
2293 add_trace("state", NULL, "connect");
2295 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2296 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2297 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2298 return; /* must exit here */
2300 case PORT_STATE_IN_ALERTING:
2301 add_trace("state", NULL, "incoming alerting");
2302 param->disconnectinfo.cause = CAUSE_NOANSWER;
2303 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2306 case PORT_STATE_IN_DISCONNECT:
2307 case PORT_STATE_OUT_DISCONNECT:
2308 add_trace("state", NULL, "disconnect");
2310 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2311 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2312 return; /* must exit here */
2315 param->disconnectinfo.cause = 31; /* normal unspecified */
2316 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2319 /* release call, disconnect isdn */
2321 new_state(EPOINT_STATE_OUT_DISCONNECT);
2322 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2323 SCPY(e_tone, cause);
2325 set_tone(portlist, cause);
2326 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2327 portlist = portlist->next;
2329 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2332 /* port MESSAGE_NOTIFY */
2333 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2335 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2337 struct lcr_msg *message;
2338 const char *logtext = "";
2341 /* signal to call tool */
2342 admin_call_response(e_adminid, ADMIN_CALL_NOTIFY, numberrize_callerinfo(param->notifyinfo.id,param->notifyinfo.ntype, options.national, options.international), 0, 0, param->notifyinfo.notify);
2343 if (param->notifyinfo.notify) {
2344 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2347 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2348 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2349 case INFO_NOTIFY_REMOTE_HOLD:
2350 case INFO_NOTIFY_USER_SUSPENDED:
2351 /* tell call about it */
2352 if (ea_endpoint->ep_join_id) {
2353 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2354 message->param.audiopath = 0;
2355 message_put(message);
2359 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2360 case INFO_NOTIFY_USER_RESUMED:
2361 /* set volume of rx and tx */
2362 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2363 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2365 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2366 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2367 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2368 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2369 message_put(message);
2371 /* set current tone */
2373 set_tone(portlist, e_tone);
2374 /* tell call about it */
2375 if (ea_endpoint->ep_join_id) {
2376 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2377 message->param.audiopath = 1;
2378 message_put(message);
2383 /* get name of notify */
2384 switch(param->notifyinfo.notify) {
2389 logtext = "USER_SUSPENDED";
2392 logtext = "BEARER_SERVICE_CHANGED";
2395 logtext = "USER_RESUMED";
2398 logtext = "CONFERENCE_ESTABLISHED";
2401 logtext = "CONFERENCE_DISCONNECTED";
2404 logtext = "OTHER_PARTY_ADDED";
2407 logtext = "ISOLATED";
2410 logtext = "REATTACHED";
2413 logtext = "OTHER_PARTY_ISOLATED";
2416 logtext = "OTHER_PARTY_REATTACHED";
2419 logtext = "OTHER_PARTY_SPLIT";
2422 logtext = "OTHER_PARTY_DISCONNECTED";
2425 logtext = "CONFERENCE_FLOATING";
2428 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2431 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2434 logtext = "CALL_IS_A_WAITING_CALL";
2437 logtext = "DIVERSION_ACTIVATED";
2440 logtext = "RESERVED_CT_1";
2443 logtext = "RESERVED_CT_2";
2446 logtext = "REVERSE_CHARGING";
2449 logtext = "REMOTE_HOLD";
2452 logtext = "REMOTE_RETRIEVAL";
2455 logtext = "CALL_IS_DIVERTING";
2458 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2463 /* notify call if available */
2464 if (ea_endpoint->ep_join_id) {
2465 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2466 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2467 message_put(message);
2472 /* port MESSAGE_PROGRESS */
2473 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2475 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2477 struct lcr_msg *message;
2479 /* signal to call tool */
2480 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2482 /* send progress to call if available */
2483 if (ea_endpoint->ep_join_id) {
2484 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2485 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2486 message_put(message);
2491 /* port MESSAGE_FACILITY */
2492 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2494 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2496 struct lcr_msg *message;
2498 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2499 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2500 message_put(message);
2503 /* port MESSAGE_SUSPEND */
2504 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2505 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2507 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2509 /* epoint is now parked */
2510 ea_endpoint->ep_park = 1;
2511 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2512 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2514 /* remove port relation */
2515 ea_endpoint->free_portlist(portlist);
2518 /* port MESSAGE_RESUME */
2519 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2520 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2522 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2524 /* epoint is now resumed */
2525 ea_endpoint->ep_park = 0;
2530 /* port sends message to the endpoint
2532 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2534 struct port_list *portlist;
2536 portlist = ea_endpoint->ep_portlist;
2538 if (port_id == portlist->port_id)
2540 portlist = portlist->next;
2543 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);
2547 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2548 switch(message_type) {
2549 case MESSAGE_DATA: /* data from port */
2550 /* check if there is a call */
2551 if (!ea_endpoint->ep_join_id)
2553 /* continue if only one portlist */
2554 if (ea_endpoint->ep_portlist->next != NULL)
2556 /* forward message */
2557 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2560 case MESSAGE_TONE_EOF: /* tone is end of file */
2561 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2563 if (e_action->index == ACTION_VBOX_PLAY) {
2566 if (e_action->index == ACTION_EFI) {
2572 case MESSAGE_TONE_COUNTER: /* counter info received */
2573 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);
2575 if (e_action->index == ACTION_VBOX_PLAY) {
2576 e_vbox_counter = param->counter.current;
2577 if (param->counter.max >= 0)
2578 e_vbox_counter_max = param->counter.max;
2582 /* PORT sends SETUP message */
2584 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);
2585 if (e_state!=EPOINT_STATE_IDLE) {
2586 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2589 port_setup(portlist, message_type, param);
2592 /* PORT sends INFORMATION message */
2593 case MESSAGE_INFORMATION: /* additional digits received */
2594 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);
2595 port_information(portlist, message_type, param);
2598 /* PORT sends FACILITY message */
2599 case MESSAGE_FACILITY:
2600 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2601 port_facility(portlist, message_type, param);
2604 /* PORT sends DTMF message */
2605 case MESSAGE_DTMF: /* dtmf digits received */
2606 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);
2607 port_dtmf(portlist, message_type, param);
2610 /* PORT sends CRYPT message */
2611 case MESSAGE_CRYPT: /* crypt response received */
2612 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2613 port_crypt(portlist, message_type, param);
2616 /* PORT sends MORE message */
2617 case MESSAGE_OVERLAP:
2618 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);
2619 if (e_state != EPOINT_STATE_OUT_SETUP) {
2620 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);
2623 port_overlap(portlist, message_type, param);
2626 /* PORT sends PROCEEDING message */
2627 case MESSAGE_PROCEEDING: /* port is proceeding */
2628 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);
2629 if (e_state!=EPOINT_STATE_OUT_SETUP
2630 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2631 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);
2634 port_proceeding(portlist, message_type, param);
2637 /* PORT sends ALERTING message */
2638 case MESSAGE_ALERTING:
2639 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);
2640 if (e_state!=EPOINT_STATE_OUT_SETUP
2641 && e_state!=EPOINT_STATE_OUT_OVERLAP
2642 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2643 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);
2646 port_alerting(portlist, message_type, param);
2649 /* PORT sends CONNECT message */
2650 case MESSAGE_CONNECT:
2651 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);
2652 if (e_state!=EPOINT_STATE_OUT_SETUP
2653 && e_state!=EPOINT_STATE_OUT_OVERLAP
2654 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2655 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2656 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2659 port_connect(portlist, message_type, param);
2662 /* PORT sends DISCONNECT message */
2663 case MESSAGE_DISCONNECT: /* port is disconnected */
2664 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);
2665 port_disconnect_release(portlist, message_type, param);
2668 /* PORT sends a RELEASE message */
2669 case MESSAGE_RELEASE: /* port releases */
2670 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);
2671 /* portlist is release at port_disconnect_release, thanx Paul */
2672 port_disconnect_release(portlist, message_type, param);
2675 /* PORT sends a TIMEOUT message */
2676 case MESSAGE_TIMEOUT:
2677 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);
2678 port_timeout(portlist, message_type, param);
2679 break; /* release */
2681 /* PORT sends a NOTIFY message */
2682 case MESSAGE_NOTIFY:
2683 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);
2684 port_notify(portlist, message_type, param);
2687 /* PORT sends a PROGRESS message */
2688 case MESSAGE_PROGRESS:
2689 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received progress.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2690 port_progress(portlist, message_type, param);
2693 /* PORT sends a SUSPEND message */
2694 case MESSAGE_SUSPEND:
2695 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);
2696 port_suspend(portlist, message_type, param);
2697 break; /* suspend */
2699 /* PORT sends a RESUME message */
2700 case MESSAGE_RESUME:
2701 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);
2702 port_resume(portlist, message_type, param);
2706 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2707 /* port assigns bchannel */
2708 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2709 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);
2710 /* only one port is expected to be connected to bchannel */
2711 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2712 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2718 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);
2721 /* Note: this endpoint may be destroyed, so we MUST return */
2725 /* messages from join
2727 /* join MESSAGE_CRYPT */
2728 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2730 switch(param->crypt.type) {
2731 /* message from remote port to "crypt manager" */
2732 case CU_ACTK_REQ: /* activate key-exchange */
2733 case CU_ACTS_REQ: /* activate shared key */
2734 case CU_DACT_REQ: /* deactivate */
2735 case CU_INFO_REQ: /* request last info message */
2736 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2739 /* message from "crypt manager" to user */
2740 case CU_ACTK_CONF: /* key-echange done */
2741 case CU_ACTS_CONF: /* shared key done */
2742 case CU_DACT_CONF: /* deactivated */
2743 case CU_DACT_IND: /* deactivated */
2744 case CU_ERROR_IND: /* receive error message */
2745 case CU_INFO_IND: /* receive info message */
2746 case CU_INFO_CONF: /* receive info message */
2747 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2751 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);
2755 /* join MESSAGE_INFORMATION */
2756 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2758 struct lcr_msg *message;
2763 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2764 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2765 message_put(message);
2766 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2767 portlist = portlist->next;
2771 /* join MESSAGE_FACILITY */
2772 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2774 struct lcr_msg *message;
2776 if (!e_ext.facility && e_ext.number[0]) {
2781 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2782 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2783 message_put(message);
2784 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2785 portlist = portlist->next;
2789 /* join MESSAGE_MORE */
2790 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2792 struct lcr_msg *message;
2794 new_state(EPOINT_STATE_IN_OVERLAP);
2797 if (e_join_pattern && e_ext.own_setup) {
2798 /* disconnect audio */
2799 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2800 message->param.audiopath = 0;
2801 message_put(message);
2803 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2804 if (e_dialinginfo.id[0])
2805 set_tone(portlist, "dialing");
2807 set_tone(portlist, "dialtone");
2810 if (e_dialinginfo.id[0]) {
2811 set_tone(portlist, "dialing");
2813 if (e_ext.number[0])
2814 set_tone(portlist, "dialpbx");
2816 set_tone(portlist, "dialtone");
2820 /* join MESSAGE_PROCEEDING */
2821 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2823 struct lcr_msg *message;
2825 new_state(EPOINT_STATE_IN_PROCEEDING);
2827 /* own proceeding tone */
2828 if (e_join_pattern) {
2829 /* connect / disconnect audio */
2830 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2831 if (e_ext.own_proceeding)
2832 message->param.audiopath = 0;
2834 message->param.audiopath = 1;
2835 message_put(message);
2837 // UCPY(e_join_tone, "proceeding");
2839 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2840 message_put(message);
2841 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2843 set_tone(portlist, "proceeding");
2846 /* join MESSAGE_ALERTING */
2847 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2849 struct lcr_msg *message;
2851 new_state(EPOINT_STATE_IN_ALERTING);
2853 /* own alerting tone */
2854 if (e_join_pattern) {
2855 /* connect / disconnect audio */
2856 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2857 if (e_ext.own_alerting)
2858 message->param.audiopath = 0;
2860 message->param.audiopath = 1;
2861 message_put(message);
2864 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2865 message_put(message);
2866 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2868 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2869 set_tone(portlist, "ringing");
2872 if (e_ext.number[0])
2873 set_tone(portlist, "ringpbx");
2875 set_tone(portlist, "ringing");
2877 if (e_ext.number[0])
2878 e_dtmf = 1; /* allow dtmf */
2881 /* join MESSAGE_CONNECT */
2882 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2884 struct lcr_msg *message;
2887 new_state(EPOINT_STATE_CONNECT);
2888 // UCPY(e_join_tone, "");
2890 if (e_ext.number[0])
2891 e_dtmf = 1; /* allow dtmf */
2894 unsched_timer(&e_powerdial_timeout);
2895 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2897 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2898 memcpy(&message->param, param, sizeof(union parameter));
2900 /* screen clip if prefix is required */
2901 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
2902 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2903 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
2904 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2907 /* use internal caller id */
2908 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
2909 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2910 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2913 /* handle restricted caller ids */
2914 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);
2915 /* display callerid if desired for extension */
2916 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));
2918 /* use conp, if enabld */
2919 // if (!e_ext.centrex)
2920 // message->param.connectinfo.name[0] = '\0';
2923 message_put(message);
2924 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2926 set_tone(portlist, NULL);
2928 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2929 message->param.audiopath = 1;
2930 message_put(message);
2935 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
2936 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
2939 struct lcr_msg *message;
2940 struct port_list *portlist = NULL;
2944 /* be sure that we are active */
2946 e_tx_state = NOTIFY_STATE_ACTIVE;
2948 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
2949 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
2950 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
2952 /* set time for power dialing */
2953 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
2956 /* set redial tone */
2957 if (ea_endpoint->ep_portlist) {
2960 set_tone(ea_endpoint->ep_portlist, "redial");
2961 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);
2962 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
2963 if (e_state==EPOINT_STATE_IN_OVERLAP) {
2964 new_state(EPOINT_STATE_IN_PROCEEDING);
2965 if (ea_endpoint->ep_portlist) {
2966 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2967 message_put(message);
2968 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2970 /* caused the error, that the first knock sound was not there */
2971 /* set_tone(portlist, "proceeding"); */
2973 /* send display of powerdialing */
2974 if (e_ext.display_dialing) {
2975 portlist = ea_endpoint->ep_portlist;
2977 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
2979 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
2981 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
2982 message_put(message);
2983 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2984 portlist = portlist->next;
2994 if ((e_state!=EPOINT_STATE_CONNECT
2995 && e_state!=EPOINT_STATE_OUT_DISCONNECT
2996 && e_state!=EPOINT_STATE_IN_OVERLAP
2997 && e_state!=EPOINT_STATE_IN_PROCEEDING
2998 && e_state!=EPOINT_STATE_IN_ALERTING)
2999 || !ea_endpoint->ep_portlist) { /* or no port */
3000 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3001 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3002 return; /* must exit here */
3005 if (!e_join_cause) {
3006 e_join_cause = param->disconnectinfo.cause;
3007 e_join_location = param->disconnectinfo.location;
3010 /* on release we need the audio again! */
3011 if (message_type == MESSAGE_RELEASE) {
3013 ea_endpoint->ep_join_id = 0;
3015 /* disconnect and select tone */
3016 new_state(EPOINT_STATE_OUT_DISCONNECT);
3017 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3018 /* if own_cause, we must release the join */
3019 if (e_ext.own_cause /* own cause */
3020 || !e_join_pattern) { /* no patterns */
3021 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);
3022 if (message_type != MESSAGE_RELEASE)
3023 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3025 } else { /* else we enable audio */
3026 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3027 message->param.audiopath = 1;
3028 message_put(message);
3030 /* send disconnect message */
3031 SCPY(e_tone, cause);
3032 portlist = ea_endpoint->ep_portlist;
3034 set_tone(portlist, cause);
3035 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3036 portlist = portlist->next;
3040 /* join MESSAGE_SETUP */
3041 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3043 struct lcr_msg *message;
3044 // struct interface *interface;
3046 /* if we already in setup state, we just update the dialing with new digits */
3047 if (e_state == EPOINT_STATE_OUT_SETUP
3048 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3049 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3050 /* if digits changed, what we have already dialed */
3051 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3052 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);
3053 /* release all ports */
3054 while((portlist = ea_endpoint->ep_portlist)) {
3055 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3056 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3057 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3058 message_put(message);
3059 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3060 ea_endpoint->free_portlist(portlist);
3063 /* disconnect audio */
3064 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3065 message->param.audiopath = 0;
3066 message_put(message);
3068 /* get dialing info */
3069 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3070 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3071 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3072 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3073 new_state(EPOINT_STATE_OUT_OVERLAP);
3076 schedule_timer(&e_redial_timeout, 1, 0);
3079 /* if we have a pending redial, so we just adjust the dialing number */
3080 if (e_redial_timeout.active) {
3081 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);
3082 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3085 if (!ea_endpoint->ep_portlist) {
3086 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3088 if (ea_endpoint->ep_portlist->next) {
3089 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3091 if (e_state == EPOINT_STATE_OUT_SETUP) {
3093 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);
3094 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3097 /* get what we have not dialed yet */
3098 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));
3099 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3100 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3101 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3102 message_put(message);
3103 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3105 /* always store what we have dialed or queued */
3106 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3110 if (e_state != EPOINT_STATE_IDLE) {
3111 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3114 /* if an internal extension is dialed, copy that number */
3115 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3116 SCPY(e_ext.number, param->setup.dialinginfo.id);
3117 /* if an internal extension is dialed, get extension's info about caller */
3118 if (e_ext.number[0]) {
3119 if (!read_extension(&e_ext, e_ext.number)) {
3120 e_ext.number[0] = '\0';
3121 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3125 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3126 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3127 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3128 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3130 /* process (voice over) data calls */
3131 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3132 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3133 memset(&e_capainfo, 0, sizeof(e_capainfo));
3134 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3135 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3136 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3139 new_state(EPOINT_STATE_OUT_SETUP);
3140 /* call special setup routine */
3144 /* join MESSAGE_mISDNSIGNAL */
3145 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3147 struct lcr_msg *message;
3150 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3151 memcpy(&message->param, param, sizeof(union parameter));
3152 message_put(message);
3153 portlist = portlist->next;
3157 /* join MESSAGE_NOTIFY */
3158 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3160 struct lcr_msg *message;
3163 if (param->notifyinfo.notify) {
3164 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3165 // /* if notification was generated locally, we turn hold music on/off */
3166 // if (param->notifyinfo.local)
3167 // 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)
3171 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3172 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3174 set_tone(portlist, "");
3175 portlist = portlist->next;
3178 portlist = ea_endpoint->ep_portlist;
3183 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3185 set_tone(portlist, "hold");
3186 portlist = portlist->next;
3188 portlist = ea_endpoint->ep_portlist;
3193 /* save new state */
3194 e_tx_state = new_state;
3197 /* notify port(s) about it */
3199 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3200 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3201 /* handle restricted caller ids */
3202 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3203 /* display callerid if desired for extension */
3204 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));
3205 message_put(message);
3206 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3207 portlist = portlist->next;
3211 /* JOIN sends messages to the endpoint
3213 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3215 struct port_list *portlist;
3216 struct lcr_msg *message;
3219 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3223 portlist = ea_endpoint->ep_portlist;
3225 /* send MESSAGE_DATA to port */
3226 if (message_type == MESSAGE_DATA) {
3227 if (join_id == ea_endpoint->ep_join_id) { // still linked with JOIN
3228 /* skip if no port relation */
3231 /* skip if more than one port relation */
3234 /* forward audio data to port */
3235 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3240 // 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);
3241 switch(message_type) {
3242 /* JOIN SENDS TONE message */
3244 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);
3245 set_tone(portlist, param->tone.name);
3248 /* JOIN SENDS CRYPT message */
3250 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);
3251 join_crypt(portlist, message_type, param);
3254 /* JOIN sends INFORMATION message */
3255 case MESSAGE_INFORMATION:
3256 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);
3257 join_information(portlist, message_type, param);
3260 /* JOIN sends FACILITY message */
3261 case MESSAGE_FACILITY:
3262 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);
3263 join_facility(portlist, message_type, param);
3266 /* JOIN sends OVERLAP message */
3267 case MESSAGE_OVERLAP:
3268 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);
3269 if (e_state!=EPOINT_STATE_IN_SETUP
3270 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3271 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3274 join_overlap(portlist, message_type, param);
3277 /* JOIN sends PROCEEDING message */
3278 case MESSAGE_PROCEEDING:
3279 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);
3280 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3281 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3284 join_proceeding(portlist, message_type, param);
3287 /* JOIN sends ALERTING message */
3288 case MESSAGE_ALERTING:
3289 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);
3290 if (e_state!=EPOINT_STATE_IN_OVERLAP
3291 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3292 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3295 join_alerting(portlist, message_type, param);
3298 /* JOIN sends CONNECT message */
3299 case MESSAGE_CONNECT:
3300 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);
3301 if (e_state!=EPOINT_STATE_IN_OVERLAP
3302 && e_state!=EPOINT_STATE_IN_PROCEEDING
3303 && e_state!=EPOINT_STATE_IN_ALERTING) {
3304 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3307 join_connect(portlist, message_type, param);
3310 /* JOIN sends DISCONNECT/RELEASE message */
3311 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3312 case MESSAGE_RELEASE: /* JOIN releases */
3313 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);
3314 join_disconnect_release(message_type, param);
3317 /* JOIN sends SETUP message */
3319 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);
3320 join_setup(portlist, message_type, param);
3323 /* JOIN sends special mISDNSIGNAL message */
3324 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3325 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);
3326 join_mISDNsignal(portlist, message_type, param);
3330 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
3331 /* JOIN requests bchannel */
3332 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3333 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);
3334 /* only one port is expected to be connected to bchannel */
3341 set_tone(portlist, NULL);
3342 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3343 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3347 /* JOIN has pattern available */
3348 case MESSAGE_PATTERN: /* indicating pattern available */
3349 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);
3350 if (!e_join_pattern) {
3351 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3355 set_tone(portlist, NULL);
3356 portlist = portlist->next;
3358 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3359 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3360 message->param.audiopath = 1;
3361 message_put(message);
3365 /* JOIN has no pattern available */
3366 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3367 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);
3368 if (e_join_pattern) {
3369 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3371 /* disconnect our audio tx and rx */
3372 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3373 message->param.audiopath = 0;
3374 message_put(message);
3379 /* JOIN (dunno at the moment) */
3380 case MESSAGE_REMOTE_AUDIO:
3381 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);
3382 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3383 message->param.audiopath = param->channel;
3384 message_put(message);
3388 /* JOIN sends a notify message */
3389 case MESSAGE_NOTIFY:
3390 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);
3391 join_notify(portlist, message_type, param);
3394 /* JOIN wants keypad / dtmf */
3395 case MESSAGE_ENABLEKEYPAD:
3396 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);
3399 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3404 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);
3409 /* pick_join will connect the first incoming call found. the endpoint
3410 * will receivce a MESSAGE_CONNECT.
3412 int match_list(char *list, char *item)
3414 char *end, *next = NULL;
3416 /* no list make matching */
3421 /* eliminate white spaces */
3422 while (*list <= ' ')
3428 /* if end of list is reached, we return */
3429 if (list[0] == '\0')
3431 /* if we have more than one entry (left) */
3432 if ((end = strchr(list, ',')))
3435 next = end = strchr(list, '\0');
3436 while (*(end-1) <= ' ')
3438 /* if string part matches item */
3439 if (!strncmp(list, item, end-list))
3445 void EndpointAppPBX::pick_join(char *extensions)
3447 struct lcr_msg *message;
3448 struct port_list *portlist;
3450 class EndpointAppPBX *eapp, *found;
3452 class JoinPBX *joinpbx;
3453 struct join_relation *relation;
3456 /* find an endpoint that is ringing internally or vbox with higher priority */
3459 eapp = apppbx_first;
3461 if (eapp!=this && ea_endpoint->ep_portlist) {
3462 portlist = eapp->ea_endpoint->ep_portlist;
3464 if ((port = find_port_id(portlist->port_id))) {
3465 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3466 if (match_list(extensions, eapp->e_ext.number)) {
3472 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
3473 && port->p_state==PORT_STATE_OUT_ALERTING)
3474 if (match_list(extensions, eapp->e_ext.number)) {
3478 portlist = portlist->next;
3486 /* if no endpoint found */
3488 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);
3490 set_tone(ea_endpoint->ep_portlist, "cause_10");
3491 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3492 new_state(EPOINT_STATE_OUT_DISCONNECT);
3497 if (ea_endpoint->ep_join_id) {
3498 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3501 if (!eapp->ea_endpoint->ep_join_id) {
3502 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3505 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3507 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3510 if (join->j_type != JOIN_TYPE_PBX) {
3511 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3514 joinpbx = (class JoinPBX *)join;
3515 relation = joinpbx->j_relation;
3517 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3520 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3521 relation = relation->next;
3523 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3528 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3530 if (options.deb & DEBUG_EPOINT) {
3531 class Join *debug_c = join_first;
3532 class Endpoint *debug_e = epoint_first;
3533 class Port *debug_p = port_first;
3535 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3537 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3539 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3540 debug_c = debug_c->next;
3542 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3544 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3545 debug_e = debug_e->next;
3547 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3549 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3550 debug_p = debug_p->next;
3555 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3556 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3557 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3559 /* connnecting our endpoint */
3560 new_state(EPOINT_STATE_CONNECT);
3561 if (e_ext.number[0])
3563 set_tone(ea_endpoint->ep_portlist, NULL);
3565 /* now we send a release to the ringing endpoint */
3566 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3567 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3568 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3569 message_put(message);
3571 /* we send a connect to the join with our caller id */
3572 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3573 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3574 message->param.connectinfo.present = e_callerinfo.present;
3575 message->param.connectinfo.screen = e_callerinfo.screen;
3576 message->param.connectinfo.itype = e_callerinfo.itype;
3577 message->param.connectinfo.ntype = e_callerinfo.ntype;
3578 message_put(message);
3580 /* we send a connect to our port with the remote callerid */
3581 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3582 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3583 message->param.connectinfo.present = eapp->e_callerinfo.present;
3584 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3585 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3586 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3587 /* handle restricted caller ids */
3588 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);
3589 /* display callerid if desired for extension */
3590 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));
3591 message_put(message);
3593 /* we send a connect to the audio path (not for vbox) */
3594 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3595 message->param.audiopath = 1;
3596 message_put(message);
3598 /* beeing paranoid, we make call update */
3599 trigger_work(&joinpbx->j_updatebridge);
3601 if (options.deb & DEBUG_EPOINT) {
3602 class Join *debug_c = join_first;
3603 class Endpoint *debug_e = epoint_first;
3604 class Port *debug_p = port_first;
3606 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3608 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3610 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3611 debug_c = debug_c->next;
3613 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3615 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3616 debug_e = debug_e->next;
3618 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3620 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3621 debug_p = debug_p->next;
3627 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3629 void EndpointAppPBX::join_join(void)
3631 struct lcr_msg *message;
3632 struct join_relation *our_relation, *other_relation;
3633 struct join_relation **our_relation_pointer, **other_relation_pointer;
3634 class Join *our_join, *other_join;
3635 class JoinPBX *our_joinpbx, *other_joinpbx;
3636 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3637 class Port *our_port, *other_port;
3638 class Pdss1 *our_pdss1, *other_pdss1;
3640 /* are we a candidate to join a join? */
3641 our_join = find_join_id(ea_endpoint->ep_join_id);
3643 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3646 if (our_join->j_type != JOIN_TYPE_PBX) {
3647 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3650 our_joinpbx = (class JoinPBX *)our_join;
3651 if (!ea_endpoint->ep_portlist) {
3652 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3655 if (!e_ext.number[0]) {
3656 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3659 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3661 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3664 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1) {
3665 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3668 our_pdss1 = (class Pdss1 *)our_port;
3670 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3671 other_eapp = apppbx_first;
3673 if (other_eapp == this) {
3674 other_eapp = other_eapp->next;
3677 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);
3678 if (other_eapp->e_ext.number[0] /* has terminal */
3679 && other_eapp->ea_endpoint->ep_portlist /* has port */
3680 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3681 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3682 if (other_port) { /* port still exists */
3683 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3684 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3685 other_pdss1 = (class Pdss1 *)other_port;
3686 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);
3687 if (other_pdss1->p_m_hold /* port is on hold */
3688 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3689 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3692 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3695 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3698 other_eapp = other_eapp->next;
3701 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3704 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3706 /* if we have the same join */
3707 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3708 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3711 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3713 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3716 if (other_join->j_type != JOIN_TYPE_PBX) {
3717 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3720 other_joinpbx = (class JoinPBX *)other_join;
3721 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3722 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3726 /* remove relation to endpoint for join on hold */
3727 other_relation = other_joinpbx->j_relation;
3728 other_relation_pointer = &other_joinpbx->j_relation;
3729 while(other_relation) {
3730 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3731 /* detach other endpoint on hold */
3732 *other_relation_pointer = other_relation->next;
3733 FREE(other_relation, sizeof(struct join_relation));
3735 other_relation = *other_relation_pointer;
3736 other_eapp->ea_endpoint->ep_join_id = 0;
3740 /* change join/hold pointer of endpoint to the new join */
3741 temp_epoint = find_epoint_id(other_relation->epoint_id);
3743 if (temp_epoint->ep_join_id == other_join->j_serial)
3744 temp_epoint->ep_join_id = our_join->j_serial;
3747 other_relation_pointer = &other_relation->next;
3748 other_relation = other_relation->next;
3750 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3752 /* join call relations */
3753 our_relation = our_joinpbx->j_relation;
3754 our_relation_pointer = &our_joinpbx->j_relation;
3755 while(our_relation) {
3756 our_relation_pointer = &our_relation->next;
3757 our_relation = our_relation->next;
3759 *our_relation_pointer = other_joinpbx->j_relation;
3760 other_joinpbx->j_relation = NULL;
3761 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3763 /* release endpoint on hold */
3764 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3765 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3766 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3767 message_put(message);
3769 /* if we are not a partyline, we get partyline state from other join */
3770 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3772 /* remove empty join */
3774 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3776 /* mixer must update */
3777 trigger_work(&our_joinpbx->j_updatebridge);
3779 /* we send a retrieve to that endpoint */
3780 // mixer will update the hold-state of the join and send it to the endpoints is changes
3784 /* check if we have an external call
3785 * this is used to check for encryption ability
3787 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3789 struct join_relation *relation;
3791 class JoinPBX *joinpbx;
3792 class Endpoint *epoint;
3794 /* some paranoia check */
3795 if (!ea_endpoint->ep_portlist) {
3796 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3797 *errstr = "No Call";
3800 if (!e_ext.number[0]) {
3801 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3802 *errstr = "No Call";
3806 /* check if we have a join with 2 parties */
3807 join = find_join_id(ea_endpoint->ep_join_id);
3809 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3810 *errstr = "No Call";
3813 if (join->j_type != JOIN_TYPE_PBX) {
3814 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3815 *errstr = "No PBX Call";
3818 joinpbx = (class JoinPBX *)join;
3819 relation = joinpbx->j_relation;
3821 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3822 *errstr = "No Call";
3825 if (!relation->next) {
3826 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3827 *errstr = "No Call";
3830 if (relation->next->next) {
3831 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3832 *errstr = "Err: Conference";
3835 if (relation->epoint_id == ea_endpoint->ep_serial) {
3836 relation = relation->next;
3837 if (relation->epoint_id == ea_endpoint->ep_serial) {
3838 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3839 *errstr = "Software Error";
3844 /* check remote port for external call */
3845 epoint = find_epoint_id(relation->epoint_id);
3847 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3848 *errstr = "No Call";
3851 if (!epoint->ep_portlist) {
3852 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3853 *errstr = "No Call";
3856 *port = find_port_id(epoint->ep_portlist->port_id);
3858 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3859 *errstr = "No Call";
3862 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) { /* port is not external isdn */
3863 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
3864 *errstr = "No Ext Call";
3867 if ((*port)->p_state != PORT_STATE_CONNECT) {
3868 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
3869 *errstr = "No Ext Connect";
3875 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
3877 const char *logtext = "unknown";
3880 switch(message_type) {
3882 trace_header("SETUP", dir);
3883 if (dir == DIRECTION_OUT)
3884 add_trace("to", NULL, "CH(%lu)", port_id);
3885 if (dir == DIRECTION_IN)
3886 add_trace("from", NULL, "CH(%lu)", port_id);
3887 if (param->setup.callerinfo.extension[0])
3888 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
3889 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
3890 switch(param->setup.callerinfo.present) {
3891 case INFO_PRESENT_RESTRICTED:
3892 add_trace("caller id", "present", "restricted");
3894 case INFO_PRESENT_ALLOWED:
3895 add_trace("caller id", "present", "allowed");
3898 add_trace("caller id", "present", "not available");
3900 if (param->setup.callerinfo.ntype2) {
3901 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
3902 switch(param->setup.callerinfo.present) {
3903 case INFO_PRESENT_RESTRICTED:
3904 add_trace("caller id2", "present", "restricted");
3906 case INFO_PRESENT_ALLOWED:
3907 add_trace("caller id2", "present", "allowed");
3910 add_trace("caller id2", "present", "not available");
3913 if (param->setup.redirinfo.id[0]) {
3914 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
3915 switch(param->setup.redirinfo.present) {
3916 case INFO_PRESENT_RESTRICTED:
3917 add_trace("redir'ing", "present", "restricted");
3919 case INFO_PRESENT_ALLOWED:
3920 add_trace("redir'ing", "present", "allowed");
3923 add_trace("redir'ing", "present", "not available");
3926 if (param->setup.dialinginfo.id[0])
3927 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
3928 if (param->setup.dialinginfo.keypad[0])
3929 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
3930 if (param->setup.dialinginfo.display[0])
3931 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
3932 if (param->setup.dialinginfo.sending_complete)
3933 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
3937 case MESSAGE_OVERLAP:
3938 trace_header("SETUP ACKNOWLEDGE", 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);
3946 case MESSAGE_PROCEEDING:
3947 trace_header("PROCEEDING", dir);
3948 if (dir == DIRECTION_OUT)
3949 add_trace("to", NULL, "CH(%lu)", port_id);
3950 if (dir == DIRECTION_IN)
3951 add_trace("from", NULL, "CH(%lu)", port_id);
3955 case MESSAGE_ALERTING:
3956 trace_header("ALERTING", dir);
3957 if (dir == DIRECTION_OUT)
3958 add_trace("to", NULL, "CH(%lu)", port_id);
3959 if (dir == DIRECTION_IN)
3960 add_trace("from", NULL, "CH(%lu)", port_id);
3964 case MESSAGE_CONNECT:
3965 trace_header("CONNECT", dir);
3966 if (dir == DIRECTION_OUT)
3967 add_trace("to", NULL, "CH(%lu)", port_id);
3968 if (dir == DIRECTION_IN)
3969 add_trace("from", NULL, "CH(%lu)", port_id);
3970 if (param->connectinfo.extension[0])
3971 add_trace("extension", NULL, "%s", param->connectinfo.extension);
3972 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
3973 switch(param->connectinfo.present) {
3974 case INFO_PRESENT_RESTRICTED:
3975 add_trace("connect id", "present", "restricted");
3977 case INFO_PRESENT_ALLOWED:
3978 add_trace("connect id", "present", "allowed");
3981 add_trace("connect id", "present", "not available");
3983 if (param->connectinfo.display[0])
3984 add_trace("display", NULL, "%s", param->connectinfo.display);
3988 case MESSAGE_DISCONNECT:
3989 case MESSAGE_RELEASE:
3990 if (message_type == MESSAGE_DISCONNECT)
3991 trace_header("DISCONNECT", dir);
3993 trace_header("RELEASE", dir);
3994 if (dir == DIRECTION_OUT)
3995 add_trace("to", NULL, "CH(%lu)", port_id);
3996 if (dir == DIRECTION_IN)
3997 add_trace("from", NULL, "CH(%lu)", port_id);
3998 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
3999 switch(param->disconnectinfo.location) {
4001 add_trace("cause", "location", "0-User");
4003 case LOCATION_PRIVATE_LOCAL:
4004 add_trace("cause", "location", "1-Local-PBX");
4006 case LOCATION_PUBLIC_LOCAL:
4007 add_trace("cause", "location", "2-Local-Exchange");
4009 case LOCATION_TRANSIT:
4010 add_trace("cause", "location", "3-Transit");
4012 case LOCATION_PUBLIC_REMOTE:
4013 add_trace("cause", "location", "4-Remote-Exchange");
4015 case LOCATION_PRIVATE_REMOTE:
4016 add_trace("cause", "location", "5-Remote-PBX");
4018 case LOCATION_INTERNATIONAL:
4019 add_trace("cause", "location", "7-International-Exchange");
4021 case LOCATION_BEYOND:
4022 add_trace("cause", "location", "10-Beyond-Interworking");
4025 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4027 if (param->disconnectinfo.display[0])
4028 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4032 case MESSAGE_NOTIFY:
4033 switch(param->notifyinfo.notify) {
4038 logtext = "USER_SUSPENDED";
4041 logtext = "BEARER_SERVICE_CHANGED";
4044 logtext = "USER_RESUMED";
4047 logtext = "CONFERENCE_ESTABLISHED";
4050 logtext = "CONFERENCE_DISCONNECTED";
4053 logtext = "OTHER_PARTY_ADDED";
4056 logtext = "ISOLATED";
4059 logtext = "REATTACHED";
4062 logtext = "OTHER_PARTY_ISOLATED";
4065 logtext = "OTHER_PARTY_REATTACHED";
4068 logtext = "OTHER_PARTY_SPLIT";
4071 logtext = "OTHER_PARTY_DISCONNECTED";
4074 logtext = "CONFERENCE_FLOATING";
4077 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4080 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4083 logtext = "CALL_IS_A_WAITING_CALL";
4086 logtext = "DIVERSION_ACTIVATED";
4089 logtext = "RESERVED_CT_1";
4092 logtext = "RESERVED_CT_2";
4095 logtext = "REVERSE_CHARGING";
4098 logtext = "REMOTE_HOLD";
4101 logtext = "REMOTE_RETRIEVAL";
4104 logtext = "CALL_IS_DIVERTING";
4107 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4111 trace_header("NOTIFY", dir);
4112 if (dir == DIRECTION_OUT)
4113 add_trace("to", NULL, "CH(%lu)", port_id);
4114 if (dir == DIRECTION_IN)
4115 add_trace("from", NULL, "CH(%lu)", port_id);
4116 if (param->notifyinfo.notify)
4117 add_trace("indicator", NULL, "%s", logtext);
4118 if (param->notifyinfo.id[0]) {
4119 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4120 switch(param->notifyinfo.present) {
4121 case INFO_PRESENT_RESTRICTED:
4122 add_trace("redir'on", "present", "restricted");
4124 case INFO_PRESENT_ALLOWED:
4125 add_trace("redir'on", "present", "allowed");
4128 add_trace("redir'on", "present", "not available");
4131 if (param->notifyinfo.display[0])
4132 add_trace("display", NULL, "%s", param->notifyinfo.display);
4136 case MESSAGE_PROGRESS:
4137 switch(param->progressinfo.progress) {
4139 logtext = "Call is not end to end ISDN";
4142 logtext = "Destination address is non-ISDN";
4145 logtext = "Origination address is non-ISDN";
4148 logtext = "Call has returned to the ISDN";
4151 logtext = "In-band info or pattern available";
4154 SPRINT(buffer, "%d", param->progressinfo.progress);
4158 trace_header("PROGRESS", dir);
4159 if (dir == DIRECTION_OUT)
4160 add_trace("to", NULL, "CH(%lu)", port_id);
4161 if (dir == DIRECTION_IN)
4162 add_trace("from", NULL, "CH(%lu)", port_id);
4163 add_trace("indicator", NULL, "%s", logtext);
4164 switch(param->progressinfo.location) {
4166 add_trace("cause", "location", "0-User");
4168 case LOCATION_PRIVATE_LOCAL:
4169 add_trace("cause", "location", "1-Local-PBX");
4171 case LOCATION_PUBLIC_LOCAL:
4172 add_trace("cause", "location", "2-Local-Exchange");
4174 case LOCATION_TRANSIT:
4175 add_trace("cause", "location", "3-Transit");
4177 case LOCATION_PUBLIC_REMOTE:
4178 add_trace("cause", "location", "4-Remote-Exchange");
4180 case LOCATION_PRIVATE_REMOTE:
4181 add_trace("cause", "location", "5-Remote-PBX");
4183 case LOCATION_INTERNATIONAL:
4184 add_trace("cause", "location", "7-International-Exchange");
4186 case LOCATION_BEYOND:
4187 add_trace("cause", "location", "10-Beyond-Interworking");
4190 add_trace("cause", "location", "%d", param->progressinfo.location);
4195 case MESSAGE_INFORMATION:
4196 trace_header("INFORMATION", dir);
4197 if (dir == DIRECTION_OUT)
4198 add_trace("to", NULL, "CH(%lu)", port_id);
4199 if (dir == DIRECTION_IN)
4200 add_trace("from", NULL, "CH(%lu)", port_id);
4201 if (param->information.id[0])
4202 add_trace("dialing", NULL, "%s", param->information.id);
4203 if (param->information.display[0])
4204 add_trace("display", NULL, "%s", param->information.display);
4205 if (param->information.sending_complete)
4206 add_trace("complete", NULL, "true", param->information.sending_complete);
4210 case MESSAGE_FACILITY:
4211 trace_header("FACILITY", dir);
4212 if (dir == DIRECTION_OUT)
4213 add_trace("to", NULL, "CH(%lu)", port_id);
4214 if (dir == DIRECTION_IN)
4215 add_trace("from", NULL, "CH(%lu)", port_id);
4220 trace_header("TONE", dir);
4221 if (dir == DIRECTION_OUT)
4222 add_trace("to", NULL, "CH(%lu)", port_id);
4223 if (dir == DIRECTION_IN)
4224 add_trace("from", NULL, "CH(%lu)", port_id);
4225 if (param->tone.name[0]) {
4226 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4227 add_trace("name", NULL, "%s", param->tone.name);
4229 add_trace("off", NULL, NULL);
4233 case MESSAGE_SUSPEND:
4234 case MESSAGE_RESUME:
4235 if (message_type == MESSAGE_SUSPEND)
4236 trace_header("SUSPEND", dir);
4238 trace_header("RESUME", dir);
4239 if (dir == DIRECTION_OUT)
4240 add_trace("to", NULL, "CH(%lu)", port_id);
4241 if (dir == DIRECTION_IN)
4242 add_trace("from", NULL, "CH(%lu)", port_id);
4243 if (param->parkinfo.len)
4244 add_trace("length", NULL, "%d", param->parkinfo.len);
4249 case MESSAGE_BCHANNEL:
4250 trace_header("BCHANNEL", dir);
4251 switch(param->bchannel.type) {
4252 case BCHANNEL_REQUEST:
4253 add_trace("type", NULL, "request");
4255 case BCHANNEL_ASSIGN:
4256 add_trace("type", NULL, "assign");
4258 case BCHANNEL_ASSIGN_ACK:
4259 add_trace("type", NULL, "assign_ack");
4261 case BCHANNEL_REMOVE:
4262 add_trace("type", NULL, "remove");
4264 case BCHANNEL_REMOVE_ACK:
4265 add_trace("type", NULL, "remove_ack");
4268 if (param->bchannel.addr)
4269 add_trace("address", NULL, "%x", param->bchannel.addr);
4275 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4279 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4281 struct lcr_msg *message;
4285 if (!portlist->port_id)
4288 if (!e_connectedmode) {
4289 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4290 message->param.disconnectinfo.cause = cause;
4291 message->param.disconnectinfo.location = location;
4293 SCPY(message->param.disconnectinfo.display, display);
4295 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4297 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4299 SCPY(message->param.notifyinfo.display, display);
4301 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4303 message_put(message);
4304 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);