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, EAPP_TYPE_PBX)
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));
75 memset(&e_rtpinfo, 0, sizeof(struct rtp_info));
78 e_ruleset = ruleset_main;
80 e_rule = e_ruleset->rule_first;
83 e_match_to_action = NULL;
85 e_extdialing = e_dialinginfo.id;
89 // e_join_tone[0] = e_hold_tone[0] = '\0';
90 e_join_pattern /*= e_hold_pattern*/ = 0;
92 e_adminid = 0; // will be set, if call was initiated via admin socket
95 e_cbdialing[0] = '\0';
98 memset(&e_callbackinfo, 0, sizeof(struct caller_info));
104 e_multipoint_cause = 0;
105 e_multipoint_location = 0;
106 e_dialing_queue[0] = '\0';
108 e_crypt_state = CM_ST_NULL;
109 e_crypt_keyengine_busy = 0;
110 e_crypt_info[0] = '\0';
113 e_tx_state = NOTIFY_STATE_ACTIVE;
114 e_rx_state = NOTIFY_STATE_ACTIVE;
115 e_join_cause = e_join_location = 0;
116 /*********************************
117 *********************************
118 ********* ATTENTION *************
119 *********************************
120 *********************************/
121 /* if you add new values, that must be initialized, also check if they must
122 * be initialized when doing callback
128 * EpointAppPBX destructor
130 EndpointAppPBX::~EndpointAppPBX(void)
132 class EndpointAppPBX *temp, **tempp;
134 del_timer(&e_crypt_handler);
135 del_timer(&e_vbox_refresh);
136 del_timer(&e_action_timeout);
137 del_timer(&e_match_timeout);
138 del_timer(&e_redial_timeout);
139 del_timer(&e_powerdial_timeout);
140 del_timer(&e_cfnr_timeout);
141 del_timer(&e_cfnr_call_timeout);
142 del_timer(&e_callback_timeout);
143 del_timer(&e_password_timeout);
147 tempp = &apppbx_first;
156 FATAL("Endpoint not in endpoint's list.\n");
163 * trace header for application
165 void EndpointAppPBX::trace_header(const char *name, int direction)
169 char msgtext[sizeof(_trace.name)];
173 /* init trace with given values */
176 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
180 ea_endpoint->ep_serial,
187 /* set new endpoint state
189 void EndpointAppPBX::new_state(int state)
192 if (e_state != state) {
193 trace_header("NEW STATE", DIRECTION_NONE);
194 add_trace("state", "old", "%s", state_name[e_state]);
195 add_trace("state", "new", "%s", state_name[state]);
203 /* release join and port (as specified)
205 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force)
207 struct port_list *portlist;
208 struct lcr_msg *message;
211 /* message to test call */
212 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
214 /* if a release is pending */
215 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
216 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
217 if (ea_endpoint->ep_join_id) {
218 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
219 message->param.disconnectinfo.cause = joincause;
220 message->param.disconnectinfo.location = joinlocation;
221 message_put(message);
222 ea_endpoint->ep_join_id = 0;
226 if (release != RELEASE_PORT_JOINONLY) {
228 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
233 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
234 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
235 while((portlist = ea_endpoint->ep_portlist)) {
236 if (portlist->port_id) {
237 SPRINT(cause, "cause_%02x", portcause);
238 set_tone(portlist, cause);
239 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
240 message->param.disconnectinfo.cause = portcause;
241 message->param.disconnectinfo.location = portlocation;
242 message->param.disconnectinfo.force = force; // set, if port should release imediately
243 message_put(message);
244 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
246 ea_endpoint->free_portlist(portlist);
249 /* if callback is enabled, call back with the given caller id */
250 if (e_callback_timeout.active) {
251 /* reset some stuff */
252 new_state(EPOINT_STATE_IDLE);
253 memset(&e_connectinfo, 0, sizeof(struct connect_info));
254 memset(&e_redirinfo, 0, sizeof(struct redir_info));
255 e_start = e_stop = 0;
256 e_ruleset = ruleset_main;
258 e_rule = e_ruleset->rule_first;
260 unsched_timer(&e_action_timeout);
261 unsched_timer(&e_match_timeout);
262 unsched_timer(&e_cfnr_timeout);
263 unsched_timer(&e_cfnr_call_timeout);
264 e_match_to_action = NULL;
266 e_extdialing = e_dialinginfo.id;
272 e_multipoint_cause = 0;
273 e_multipoint_location = 0;
274 e_dialing_queue[0] = '\0';
276 e_crypt_state = CM_ST_NULL;
277 e_crypt_keyengine_busy = 0;
278 e_crypt_info[0] = '\0';
282 e_tx_state = NOTIFY_STATE_ACTIVE;
283 e_rx_state = NOTIFY_STATE_ACTIVE;
284 e_join_cause = e_join_location = 0;
286 /* the caller info of the callback user */
287 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
288 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
289 /* create dialing by callerinfo */
290 if (e_ext.number[0] && e_extension_interface[0]) {
291 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
292 /* create callback to the current terminal */
293 SCPY(e_dialinginfo.id, e_ext.number);
294 SCPY(e_dialinginfo.interfaces, e_extension_interface);
295 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
296 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
299 SCPY(e_dialinginfo.id, e_cbto);
301 /* numberrize caller id and use it to dial to the callback */
302 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
304 e_dialinginfo.itype = INFO_ITYPE_ISDN;
305 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
306 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
311 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
312 if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */
313 trigger_work(&ea_endpoint->ep_delete);
319 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
320 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
322 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");
324 /* caller id is not restricted, so we do nothing */
325 if (*present != INFO_PRESENT_RESTRICTED)
328 /* only extensions are restricted */
332 /* if we enabled anonymouse ignore */
333 if (ext->anon_ignore)
336 /* else we remove the caller id */
340 *ntype = INFO_NTYPE_UNKNOWN;
342 // *screen = INFO_SCREEN_USER;
343 // maybe we should not make voip address anonymous
346 // maybe it's no fraud to present extension id
348 // extension[0] = '\0';
353 /* used display message to display callerid as available */
354 char *EndpointAppPBX::apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name)
356 static char display[81];
359 const char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
361 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");
370 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
372 /* internal extension's caller id */
373 if (extension[0] && e_ext.display_int) {
375 SCAT(display, extension);
378 if (itype == INFO_ITYPE_VBOX)
379 SCAT(display, "(vbox)");
381 SCAT(display, "(int)");
384 /* external caller id */
385 if (!extension[0] && e_ext.display_ext) {
388 if (present == INFO_PRESENT_RESTRICTED)
389 SCAT(display, "anonymous");
391 SCAT(display, "unknown");
398 /* display if callerid is anonymouse but available due anon-ignore */
399 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED) {
401 SCAT(display, "unknown");
404 SCAT(display, " anon");
407 /* display if callerid is anonymouse but available due anon-ignore */
408 if (e_ext.display_fake && screen==INFO_SCREEN_USER && ntype!=INFO_NTYPE_NOTPRESENT) {
411 if (present == INFO_PRESENT_RESTRICTED)
412 SCAT(display, "anonymous");
414 SCAT(display, "unknown");
419 SCAT(display, " fake");
423 if (name[0] && e_ext.display_name) {
424 if (!display[0] && cid[0])
435 * uses the current state to notify activity
437 void EndpointAppPBX::notify_active(void)
439 struct port_list *portlist = ea_endpoint->ep_portlist;
440 struct lcr_msg *message;
444 case NOTIFY_STATE_ACTIVE:
445 /* we are already active, so we don't do anything */
448 case NOTIFY_STATE_SUSPEND:
449 notify = INFO_NOTIFY_USER_RESUMED;
451 set_tone(portlist, NULL);
452 portlist = portlist->next;
454 portlist = ea_endpoint->ep_portlist;
457 case NOTIFY_STATE_HOLD:
458 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
460 set_tone(portlist, NULL);
461 portlist = portlist->next;
463 portlist = ea_endpoint->ep_portlist;
466 case NOTIFY_STATE_CONFERENCE:
467 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
469 set_tone(portlist, NULL);
470 portlist = portlist->next;
472 portlist = ea_endpoint->ep_portlist;
476 PERROR("unknown e_tx_state = %d\n", e_tx_state);
481 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
482 message->param.notifyinfo.notify = notify;
483 message_put(message);
484 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
485 portlist = portlist->next;
491 * keypad functions during call. one example to use this is to put a call on hold or start a conference
493 void EndpointAppPBX::keypad_function(char digit)
496 /* we must be in a call, in order to send messages to the call */
497 if (e_ext.number[0] == '\0') {
498 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
503 /* join conference */
505 if (ea_endpoint->ep_join_id == 0) {
506 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
509 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
515 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
519 /* crypt key-exchange */
521 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
527 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
532 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
537 /* set tone pattern for port */
538 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
540 struct lcr_msg *message;
545 /* store for suspended processes */
549 if (e_join_pattern /* pattern are provided */
550 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
551 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
552 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
553 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
554 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
555 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
556 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
557 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
558 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
559 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
560 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
561 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
566 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
567 SCPY(message->param.tone.dir, e_ext.tones_dir);
568 SCPY(message->param.tone.name, tone);
569 message_put(message);
570 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
572 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
577 /* hunts for the given interface
578 * it does not need to have an mISDNport instance */
579 struct interface *EndpointAppPBX::hunt_interface(char *ifname)
581 struct interface *interface;
582 int there_is_an_external = 0;
584 interface = interface_first;
586 /* first find the given interface or, if not given, one with no extension */
589 if (!there_is_an_external && !(ifname && ifname[0])) {
590 trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
591 add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
597 /* check for given interface */
598 if (ifname && ifname[0]) {
599 if (!strcasecmp(interface->name, ifname)) {
600 /* found explicit interface */
601 trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
602 add_trace("interface", NULL, "%s", ifname);
607 if (interface->external) {
608 there_is_an_external = 1;
609 /* found non extension */
610 trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
611 add_trace("interface", NULL, "%s", interface->name);
617 interface = interface->next;
626 * hunts an mISDNport that is available for an outgoing call
627 * if no ifname was given, any interface that is not an extension
630 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
632 struct interface *interface;
633 struct interface_port *ifport, *ifport_start;
634 struct select_channel *selchannel;
635 struct mISDNport *mISDNport;
637 int there_is_an_external = 0;
639 interface = interface_first;
641 /* first find the given interface or, if not given, one with no extension */
644 if (!there_is_an_external && !(ifname && ifname[0])) {
645 trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
646 add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
652 /* check for given interface */
653 if (ifname && ifname[0]) {
654 if (!strcasecmp(interface->name, ifname)) {
655 /* found explicit interface */
656 trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
657 add_trace("interface", NULL, "%s", ifname);
663 if (interface->external) {
664 there_is_an_external = 1;
665 /* found non extension */
666 trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
667 add_trace("interface", NULL, "%s", interface->name);
673 interface = interface->next;
677 /* see if interface has ports */
678 if (!interface->ifport) {
680 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
681 add_trace("interface", NULL, "%s", interface->name);
683 interface = interface->next;
687 /* select port by algorithm */
688 ifport_start = interface->ifport;
690 if (interface->hunt == HUNT_ROUNDROBIN) {
691 while(ifport_start->next && index<interface->hunt_next) {
692 ifport_start = ifport_start->next;
695 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
696 add_trace("port", NULL, "%d", ifport_start->portnum);
697 add_trace("position", NULL, "%d", index);
702 ifport = ifport_start;
705 /* see if port is available */
706 if (!ifport->mISDNport) {
707 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
708 add_trace("port", NULL, "%d", ifport->portnum);
709 add_trace("position", NULL, "%d", index);
713 mISDNport = ifport->mISDNport;
715 /* see if port is administratively blocked */
717 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
718 add_trace("port", NULL, "%d", ifport->portnum);
719 add_trace("position", NULL, "%d", index);
724 /* see if link is up on PTP*/
725 if (mISDNport->l2hold && mISDNport->l2link<1) {
726 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
727 add_trace("port", NULL, "%d", ifport->portnum);
728 add_trace("position", NULL, "%d", index);
733 /* check for channel form selection list */
736 if (mISDNport->ss5) {
738 port = ss5_hunt_line(mISDNport);
740 *channel = port->p_m_b_channel;
741 trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
742 add_trace("port", NULL, "%d", ifport->portnum);
743 add_trace("position", NULL, "%d", index);
744 add_trace("channel", NULL, "%d", *channel);
750 selchannel = ifport->out_channel;
752 switch(selchannel->channel) {
753 case CHANNEL_FREE: /* free channel */
754 if (mISDNport->b_reserved >= mISDNport->b_num)
755 break; /* all channel in use or reserverd */
758 while(i < mISDNport->b_num) {
759 if (mISDNport->b_port[i] == NULL) {
760 *channel = i+1+(i>=15);
761 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
762 add_trace("port", NULL, "%d", ifport->portnum);
763 add_trace("position", NULL, "%d", index);
764 add_trace("channel", NULL, "%d", *channel);
772 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
773 add_trace("port", NULL, "%d", ifport->portnum);
774 add_trace("position", NULL, "%d", index);
778 case CHANNEL_ANY: /* don't ask for channel */
779 if (mISDNport->b_reserved >= mISDNport->b_num) {
780 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
781 add_trace("port", NULL, "%d", ifport->portnum);
782 add_trace("position", NULL, "%d", index);
783 add_trace("total", NULL, "%d", mISDNport->b_num);
784 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
786 break; /* all channel in use or reserverd */
788 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
789 add_trace("port", NULL, "%d", ifport->portnum);
790 add_trace("position", NULL, "%d", index);
792 *channel = CHANNEL_ANY;
795 case CHANNEL_NO: /* call waiting */
796 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
797 add_trace("port", NULL, "%d", ifport->portnum);
798 add_trace("position", NULL, "%d", index);
800 *channel = CHANNEL_NO;
804 if (selchannel->channel<1 || selchannel->channel==16) {
805 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
806 add_trace("port", NULL, "%d", ifport->portnum);
807 add_trace("position", NULL, "%d", index);
808 add_trace("channel", NULL, "%d", selchannel->channel);
810 break; /* invalid channels */
812 i = selchannel->channel-1-(selchannel->channel>=17);
813 if (i >= mISDNport->b_num) {
814 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
815 add_trace("port", NULL, "%d", ifport->portnum);
816 add_trace("position", NULL, "%d", index);
817 add_trace("channel", NULL, "%d", selchannel->channel);
818 add_trace("channels", NULL, "%d", mISDNport->b_num);
820 break; /* channel not in port */
822 if (mISDNport->b_port[i] == NULL) {
823 *channel = selchannel->channel;
824 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
825 add_trace("port", NULL, "%d", ifport->portnum);
826 add_trace("position", NULL, "%d", index);
827 add_trace("channel", NULL, "%d", *channel);
834 break; /* found channel */
835 selchannel = selchannel->next;
839 /* if channel was found, return mISDNport and channel */
841 /* setting next port to start next time */
842 if (interface->hunt == HUNT_ROUNDROBIN) {
846 interface->hunt_next = index;
852 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
853 add_trace("port", NULL, "%d", ifport->portnum);
854 add_trace("position", NULL, "%d", index);
858 /* go next port, until all ports are checked */
860 ifport = ifport->next;
863 ifport = interface->ifport;
865 if (ifport != ifport_start)
869 interface = interface->next;
873 return(NULL); /* no port found */
876 /* outgoing setup to port(s)
877 * ports will be created and a setup is sent if everything is ok. otherwhise
878 * the endpoint is destroyed.
880 void EndpointAppPBX::out_setup(int cfnr)
882 struct dialing_info dialinginfo;
884 struct port_list *portlist;
885 struct lcr_msg *message;
887 int cause = CAUSE_RESSOURCEUNAVAIL;
890 struct interface *interface;
891 struct mISDNport *mISDNport;
894 class EndpointAppPBX *atemp;
895 // char allowed_ports[256];
897 char ifname[sizeof(e_ext.interfaces)],
899 struct port_settings port_settings;
902 int mode = B_MODE_TRANSPARENT;
903 struct admin_list *admin;
905 /* set bchannel mode */
906 mode = e_capainfo.source_mode;
908 /* create settings for creating port */
909 memset(&port_settings, 0, sizeof(port_settings));
911 SCPY(port_settings.tones_dir, e_ext.tones_dir);
913 SCPY(port_settings.tones_dir, options.tones_dir);
914 port_settings.no_seconds = e_ext.no_seconds;
916 /* 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 */
918 /* check what dialinginfo.itype we got */
919 switch(e_dialinginfo.itype) {
920 /* *********************** call to extension or vbox */
921 case INFO_ITYPE_ISDN_EXTENSION:
922 /* check if we deny incoming calls when we use an extension */
923 if (e_ext.noknocking) {
924 atemp = apppbx_first;
927 if (!strcmp(atemp->e_ext.number, e_ext.number))
932 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
933 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
934 return; /* must exit here */
937 /* FALL THROUGH !!!! */
938 case INFO_ITYPE_VBOX:
939 /* get dialed extension's info */
940 // SCPY(exten, e_dialinginfo.id);
941 // if (strchr(exten, ','))
942 // *strchr(exten, ',') = '\0';
943 // if (!read_extension(&e_ext, exten))
944 if (!read_extension(&e_ext, e_dialinginfo.id)) {
945 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
946 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
947 return; /* must exit here */
949 e_dialinginfo.sending_complete = 1;
951 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
952 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
957 /* string from unconditional call forward (cfu) */
960 /* present to forwarded party */
961 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
962 e_callerinfo.present = INFO_PRESENT_ALLOWED;
964 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
968 /* string from busy call forward (cfb) */
971 class EndpointAppPBX *checkapp = apppbx_first;
973 if (checkapp != this) { /* any other endpoint except our own */
974 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
975 /* present to forwarded party */
976 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
977 e_callerinfo.present = INFO_PRESENT_ALLOWED;
979 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
983 checkapp = checkapp->next;
987 /* string from no-response call forward (cfnr) */
990 /* when cfnr is done, out_setup() will setup the call */
992 /* present to forwarded party */
993 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
994 e_callerinfo.present = INFO_PRESENT_ALLOWED;
998 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
999 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
1000 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
1001 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);
1005 /* call to all internal interfaces */
1006 p = e_ext.interfaces;
1007 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1010 while(*p!=',' && *p!='\0')
1012 SCCAT(ifname, *p++);
1015 /* search interface */
1016 interface = hunt_interface(ifname);
1018 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1019 add_trace("interface", NULL, "%s", ifname);
1023 /* found interface */
1024 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
1026 if (interface->gsm_bs) {
1027 SPRINT(portname, "%s-%d-out", interface->name, 0);
1028 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1032 if (interface->gsm_ms) {
1033 SPRINT(portname, "%s-%d-out", interface->name, 0);
1034 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1038 if (interface->sip) {
1039 SPRINT(portname, "%s-%d-out", interface->name, 0);
1040 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1044 /* hunt for mISDNport and create Port */
1045 mISDNport = hunt_port(ifname, &channel);
1047 trace_header("INTERFACE (busy)", DIRECTION_NONE);
1048 add_trace("interface", NULL, "%s", ifname);
1053 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1056 port = ss5_hunt_line(mISDNport);
1059 if (mISDNport->ifport->remote) {
1060 admin = admin_first;
1062 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1064 admin = admin->next;
1067 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1068 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1072 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1074 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);
1077 FATAL("Failed to create Port instance\n");
1078 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
1079 memset(&dialinginfo, 0, sizeof(dialinginfo));
1080 SCPY(dialinginfo.id, e_dialinginfo.id);
1081 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1082 dialinginfo.ntype = e_dialinginfo.ntype;
1083 /* create port_list relation */
1084 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, interface->is_earlyb == IS_YES);
1086 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1088 goto check_anycall_intern;
1090 /* directory.list */
1091 if (e_callerinfo.id[0] && e_ext.display_name) {
1092 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1094 SCPY(e_callerinfo.name, dirname);
1096 // dss1 = (class Pdss1 *)port;
1098 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1099 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1100 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1101 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1102 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1103 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1104 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1105 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1106 //terminal if (e_dialinginfo.id)
1107 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1108 /* handle restricted caller ids */
1109 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);
1110 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);
1111 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);
1112 /* display callerid if desired for extension */
1113 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));
1114 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1115 /* use cnip, if enabld */
1116 // if (!e_ext.centrex)
1117 // message->param.setup.callerinfo.name[0] = '\0';
1118 /* screen clip if prefix is required */
1119 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1120 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1121 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1122 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1124 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1125 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1126 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1127 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1129 /* use internal caller id */
1130 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1131 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1132 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1133 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1135 message_put(message);
1136 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1140 /* string from parallel call forward (cfp) */
1143 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1144 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1145 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1149 vbox_only: /* entry point for answering machine only */
1150 cfu_only: /* entry point for cfu */
1151 cfb_only: /* entry point for cfb */
1152 cfnr_only: /* entry point for cfnr */
1153 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1157 /* only if vbox should be dialed, and terminal is given */
1158 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1159 /* go to the end of p */
1162 /* answering vbox call */
1163 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1165 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1166 FATAL("No memory for VBOX Port instance\n");
1167 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1168 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1171 while(*p!=',' && *p!='\0')
1176 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1177 /* hunt for mISDNport and create Port */
1178 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1180 /* creating EXTERNAL port*/
1181 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1184 port = ss5_hunt_line(mISDNport);
1187 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);
1189 FATAL("No memory for Port instance\n");
1190 earlyb = mISDNport->earlyb;
1193 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1194 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1199 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1200 goto check_anycall_intern;
1202 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1203 memset(&dialinginfo, 0, sizeof(dialinginfo));
1204 SCPY(dialinginfo.id, cfp);
1205 dialinginfo.itype = INFO_ITYPE_ISDN;
1206 dialinginfo.ntype = e_dialinginfo.ntype;
1207 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1209 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1211 goto check_anycall_intern;
1213 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1214 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1215 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1216 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1217 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1218 /* if clip is hidden */
1219 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1220 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1221 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1222 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1223 message->param.setup.callerinfo.present = e_ext.callerid_present;
1224 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1226 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1227 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1228 //terminal if (e_dialinginfo.id)
1229 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1230 /* handle restricted caller ids */
1231 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);
1232 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);
1233 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);
1234 /* display callerid if desired for extension */
1235 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));
1236 message_put(message);
1237 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1241 check_anycall_intern:
1242 /* now we have all ports created */
1244 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1246 if (!ea_endpoint->ep_join_id)
1248 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1249 return; /* must exit here */
1253 /* *********************** external call */
1255 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1256 /* call to extenal interfaces */
1257 if (e_dialinginfo.keypad[0])
1258 p = e_dialinginfo.keypad;
1260 p = e_dialinginfo.id;
1263 while(*p!=',' && *p!='\0')
1264 SCCAT(number, *p++);
1268 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");
1269 /* search interface */
1270 interface = hunt_interface(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL);
1272 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1273 add_trace("interface", NULL, "%s", ifname);
1275 goto check_anycall_extern;
1277 /* found interface */
1279 if (interface->gsm_bs) {
1280 SPRINT(portname, "%s-%d-out", interface->name, 0);
1281 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1285 if (interface->gsm_ms) {
1286 SPRINT(portname, "%s-%d-out", interface->name, 0);
1287 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1291 if (interface->sip) {
1292 SPRINT(portname, "%s-%d-out", interface->name, 0);
1293 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1297 /* hunt for mISDNport and create Port */
1298 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1300 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1301 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1303 goto check_anycall_extern;
1305 /* creating EXTERNAL port*/
1306 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1309 port = ss5_hunt_line(mISDNport);
1312 if (mISDNport->ifport->remote) {
1313 admin = admin_first;
1315 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1317 admin = admin->next;
1320 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1321 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1325 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1327 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);
1330 FATAL("No memory for Port instance\n");
1331 earlyb = (interface->is_earlyb == IS_YES);
1332 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1333 memset(&dialinginfo, 0, sizeof(dialinginfo));
1334 if (e_dialinginfo.keypad[0])
1335 SCPY(dialinginfo.keypad, number);
1337 SCPY(dialinginfo.id, number);
1338 dialinginfo.itype = INFO_ITYPE_ISDN;
1339 dialinginfo.ntype = e_dialinginfo.ntype;
1340 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1341 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1343 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1345 goto check_anycall_extern;
1347 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1348 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1349 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1350 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1351 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1352 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1353 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1354 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1355 //terminal if (e_dialinginfo.id)
1356 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1357 /* handle restricted caller ids */
1358 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);
1359 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);
1360 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);
1361 /* display callerid if desired for extension */
1362 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));
1363 message_put(message);
1364 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1368 check_anycall_extern:
1369 /* now we have all ports created */
1371 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1373 if (!ea_endpoint->ep_join_id)
1375 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1376 return; /* must exit here */
1383 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1385 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1387 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1390 unsched_timer(&ea->e_redial_timeout);
1391 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1392 ea->e_multipoint_cause = 0;
1393 ea->e_multipoint_location = 0;
1394 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1395 ea->e_join_pattern = 0;
1396 ea->process_dialing(1);
1397 /* we must exit, because our endpoint might be gone */
1402 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1404 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1406 if (!ea->e_action) {
1407 unsched_timer(&ea->e_redial_timeout);
1408 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1409 ea->process_dialing(0);
1410 /* we must exit, because our endpoint might be gone */
1416 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1418 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1420 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1422 ea->new_state(EPOINT_STATE_OUT_SETUP);
1423 /* call special setup routine */
1429 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1431 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1433 /* leave power dialing on */
1434 ea->e_powerdial_on = 1;
1435 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1438 ea->e_ruleset = ruleset_main;
1440 ea->e_rule = ea->e_ruleset->rule_first;
1441 ea->e_action = NULL;
1442 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1443 ea->process_dialing(0);
1448 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1450 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1451 struct port_list *portlist;
1452 struct lcr_msg *message;
1454 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1456 /* release all ports */
1457 while((portlist = ea->ea_endpoint->ep_portlist)) {
1458 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1459 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1460 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1461 message_put(message);
1462 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1463 ea->ea_endpoint->free_portlist(portlist);
1466 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1467 message->param.audiopath = 0;
1468 message_put(message);
1469 /* indicate no patterns */
1470 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1471 message_put(message);
1472 /* set setup state, since we have no response from the new join */
1473 ea->new_state(EPOINT_STATE_OUT_SETUP);
1478 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1480 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1482 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);
1488 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1490 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1492 if (ea->e_state == EPOINT_STATE_IDLE) {
1493 /* epoint is idle, check callback */
1494 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1495 ea->new_state(EPOINT_STATE_OUT_SETUP);
1502 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1504 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1506 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1507 struct port_list *portlist;
1509 ea->e_ruleset = ruleset_main;
1511 ea->e_rule = ea->e_ruleset->rule_first;
1512 ea->e_action = NULL;
1513 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1514 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1516 ea->e_connectedmode = 0;
1518 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1519 portlist = ea->ea_endpoint->ep_portlist;
1521 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1522 ea->set_tone(portlist, "cause_10");
1529 /* doing a hookflash */
1530 void EndpointAppPBX::hookflash(void)
1535 /* be sure that we are active */
1537 e_tx_state = NOTIFY_STATE_ACTIVE;
1539 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1541 if (ea_endpoint->ep_use > 1) {
1542 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1545 /* dialtone after pressing the hash key */
1546 process_hangup(e_join_cause, e_join_location);
1547 e_multipoint_cause = 0;
1548 e_multipoint_location = 0;
1549 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1551 port->set_echotest(0);
1553 if (ea_endpoint->ep_join_id) {
1554 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1556 e_ruleset = ruleset_main;
1558 e_rule = e_ruleset->rule_first;
1560 new_state(EPOINT_STATE_IN_OVERLAP);
1561 e_connectedmode = 1;
1562 SCPY(e_dialinginfo.id, e_ext.prefix);
1563 e_extdialing = e_dialinginfo.id;
1565 if (e_dialinginfo.id[0]) {
1566 set_tone(ea_endpoint->ep_portlist, "dialing");
1569 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1577 /* messages from port
1579 /* port MESSAGE_SETUP */
1580 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1582 struct lcr_msg *message;
1584 int writeext; /* flags need to write extension after modification */
1587 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1589 portlist->port_type = param->setup.port_type;
1590 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1591 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1592 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1593 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1594 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
1596 /* convert (inter-)national number type */
1597 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1598 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1600 // e_dtmf = param->setup.dtmf;
1601 /* screen incoming caller id */
1602 if (e_callerinfo.interface[0]) {
1603 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface);
1604 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
1607 /* process extension */
1608 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1609 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1610 /* port makes call from extension */
1611 SCPY(e_callerinfo.extension, e_callerinfo.id);
1612 SCPY(e_ext.number, e_callerinfo.extension);
1613 SCPY(e_extension_interface, e_callerinfo.interface);
1615 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1618 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1619 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1621 /* get extension's info about caller */
1622 if (!read_extension(&e_ext, e_ext.number)) {
1623 /* extension doesn't exist */
1624 trace_header("EXTENSION (not created)", DIRECTION_IN);
1625 add_trace("extension", NULL, "%s", e_ext.number);
1627 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1628 new_state(EPOINT_STATE_OUT_DISCONNECT);
1629 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1630 e_ext.number[0] = '\0'; /* no terminal */
1635 /* put prefix (next) in front of e_dialinginfo.id */
1636 if (e_ext.next[0]) {
1637 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1638 SCPY(e_dialinginfo.id, buffer);
1639 e_ext.next[0] = '\0';
1641 } else if (e_ext.prefix[0]) {
1642 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1643 SCPY(e_dialinginfo.id, buffer);
1646 /* screen caller id by extension's config */
1647 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1649 SCPY(e_callerinfo.name, e_ext.name);
1650 /* use caller id (or if exist: id_next_call) for this call */
1651 if (e_ext.id_next_call_present >= 0) {
1652 SCPY(e_callerinfo.id, e_ext.id_next_call);
1653 /* if we restrict the pesentation */
1654 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1655 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1656 else e_callerinfo.present = e_ext.id_next_call_present;
1657 e_callerinfo.ntype = e_ext.id_next_call_type;
1658 e_ext.id_next_call_present = -1;
1661 SCPY(e_callerinfo.id, e_ext.callerid);
1662 /* if we restrict the pesentation */
1663 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1664 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1665 else e_callerinfo.present = e_ext.callerid_present;
1666 e_callerinfo.ntype = e_ext.callerid_type;
1668 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1670 /* extension is written */
1672 write_extension(&e_ext, e_ext.number);
1674 /* set volume of rx and tx */
1675 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1676 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1677 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1678 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1679 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1680 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1681 message_put(message);
1684 /* start recording if enabled */
1685 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1686 /* check if we are a terminal */
1687 if (e_ext.number[0] == '\0')
1688 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1690 port = find_port_id(portlist->port_id);
1692 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1696 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1697 /* no terminal identification */
1698 e_ext.number[0] = '\0';
1699 e_extension_interface[0] = '\0';
1700 memset(&e_ext, 0, sizeof(e_ext));
1701 e_ext.rights = 4; /* right to dial internat */
1705 e_ruleset = ruleset_main;
1707 e_rule = e_ruleset->rule_first;
1709 e_extdialing = e_dialinginfo.id;
1710 new_state(EPOINT_STATE_IN_SETUP);
1711 if (e_dialinginfo.id[0]) {
1712 set_tone(portlist, "dialing");
1714 if (e_ext.number[0])
1715 set_tone(portlist, "dialpbx");
1717 set_tone(portlist, "dialtone");
1720 if (e_state == EPOINT_STATE_IN_SETUP) {
1721 /* request MORE info, if not already at higher state */
1722 new_state(EPOINT_STATE_IN_OVERLAP);
1723 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1724 message_put(message);
1725 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1729 /* port MESSAGE_INFORMATION */
1730 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1732 struct lcr_msg *message;
1734 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1736 /* ignore information message without digit information */
1737 if (!param->information.id[0])
1742 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1744 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1749 /* if vbox_play is done, the information are just used as they come */
1751 if (e_action->index == ACTION_VBOX_PLAY) {
1752 /* concat dialing string */
1753 SCAT(e_dialinginfo.id, param->information.id);
1758 /* keypad when disconnect but in connected mode */
1759 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1760 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1761 /* processing keypad function */
1762 if (param->information.id[0] == '0') {
1768 /* keypad when connected */
1769 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1770 if (e_enablekeypad) {
1771 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1772 memcpy(&message->param, param, sizeof(union parameter));
1773 message_put(message);
1777 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1778 /* processing keypad function */
1779 if (param->information.id[0] == '0') {
1782 if (param->information.id[0])
1783 keypad_function(param->information.id[0]);
1785 if (e_ext.number[0])
1786 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1788 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1793 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1794 if (e_ext.number[0])
1795 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1797 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1801 if (!param->information.id[0])
1803 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1804 set_tone(portlist, "dialing");
1807 if (e_action->index==ACTION_OUTDIAL
1808 || e_action->index==ACTION_EXTERNAL
1809 || e_action->index==ACTION_REMOTE) {
1811 set_tone(portlist, "dialing");
1812 else if (!e_extdialing[0])
1813 set_tone(portlist, "dialing");
1815 /* concat dialing string */
1816 SCAT(e_dialinginfo.id, param->information.id);
1820 /* port MESSAGE_DTMF */
1821 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1824 struct lcr_msg *message;
1828 /* only if dtmf detection is enabled */
1830 trace_header("DTMF (disabled)", DIRECTION_IN);
1834 trace_header("DTMF", DIRECTION_IN);
1835 add_trace("digit", NULL, "%c", param->dtmf);
1839 NOTE: vbox is now handled due to overlap state
1840 /* if vbox_play is done, the dtmf digits are just used as they come */
1842 if (e_action->index == ACTION_VBOX_PLAY) {
1843 /* concat dialing string */
1844 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1845 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1846 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1849 /* continue to process *X# sequences */
1853 /* check for *X# sequence */
1854 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1855 if (e_enablekeypad) {
1856 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1857 memcpy(&message->param, param, sizeof(union parameter));
1858 message_put(message);
1861 if (e_dtmf_time+3 < now) {
1862 /* the last digit was too far in the past to be a sequence */
1863 if (param->dtmf == '*')
1864 /* only start is allowed in the sequence */
1869 /* we have a sequence of digits, see what we got */
1870 if (param->dtmf == '*')
1872 else if (param->dtmf>='0' && param->dtmf<='9') {
1873 /* we need to have a star before we receive the digit of the sequence */
1874 if (e_dtmf_last == '*')
1875 e_dtmf_last = param->dtmf;
1876 } else if (param->dtmf == '#') {
1878 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1879 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1880 if (e_dtmf_last == '0') {
1884 /* processing keypad function */
1886 keypad_function(e_dtmf_last);
1892 /* set last time of dtmf */
1897 /* check for ## hookflash during dialing */
1899 if (e_action->index==ACTION_PASSWORD
1900 || e_action->index==ACTION_PASSWORD_WRITE)
1902 if (param->dtmf=='#') { /* current digit is '#' */
1903 if (e_state==EPOINT_STATE_IN_DISCONNECT
1904 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1918 /* dialing using dtmf digit */
1919 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1920 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1921 set_tone(portlist, "dialing");
1923 /* concat dialing string */
1924 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1925 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1926 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1932 /* port MESSAGE_CRYPT */
1933 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1935 /* send crypt response to cryptman */
1936 if (param->crypt.type == CR_MESSAGE_IND)
1937 cryptman_msg2man(param->crypt.data, param->crypt.len);
1939 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1942 /* port MESSAGE_OVERLAP */
1943 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1945 struct lcr_msg *message;
1947 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1949 /* signal to call tool */
1950 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1952 if (e_dialing_queue[0] && portlist) {
1953 /* send what we have not dialed yet, because we had no setup complete */
1954 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1955 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1956 SCPY(message->param.information.id, e_dialing_queue);
1957 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1958 message_put(message);
1959 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1960 e_dialing_queue[0] = '\0';
1962 /* check if pattern is available */
1963 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1964 /* indicate patterns */
1965 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1966 message_put(message);
1968 /* connect audio, if not already */
1969 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1970 message->param.audiopath = 1;
1971 message_put(message);
1973 /* indicate no patterns */
1974 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1975 message_put(message);
1977 /* disconnect audio, if not already */
1978 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1979 message->param.audiopath = 0;
1980 message_put(message);
1982 new_state(EPOINT_STATE_OUT_OVERLAP);
1983 /* if we are in a join */
1984 if (ea_endpoint->ep_join_id) {
1985 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1986 memcpy(&message->param, param, sizeof(union parameter));
1987 message_put(message);
1991 /* port MESSAGE_PROCEEDING */
1992 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1994 struct lcr_msg *message;
1996 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1998 /* signal to call tool */
1999 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
2001 e_state = EPOINT_STATE_OUT_PROCEEDING;
2002 /* check if pattern is availatle */
2003 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
2004 /* indicate patterns */
2005 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2006 message_put(message);
2008 /* connect audio, if not already */
2009 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2010 message->param.audiopath = 1;
2011 message_put(message);
2013 /* indicate no patterns */
2014 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
2015 message_put(message);
2017 /* disconnect audio, if not already */
2018 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2019 message->param.audiopath = 0;
2020 message_put(message);
2022 /* if we are in a call */
2023 if (ea_endpoint->ep_join_id) {
2024 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2025 memcpy(&message->param, param, sizeof(union parameter));
2026 message_put(message);
2030 /* port MESSAGE_ALERTING */
2031 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
2033 struct lcr_msg *message;
2035 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2037 /* signal to call tool */
2038 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
2041 // set_tone(portlist, "hold");
2043 new_state(EPOINT_STATE_OUT_ALERTING);
2044 /* check if pattern is available */
2045 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
2046 /* indicate patterns */
2047 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2048 message_put(message);
2050 /* connect audio, if not already */
2051 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2052 message->param.audiopath = 1;
2053 message_put(message);
2055 /* indicate no patterns */
2056 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
2057 message_put(message);
2059 /* disconnect audio, if not already */
2060 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2061 message->param.audiopath = 0;
2062 message_put(message);
2064 /* if we are in a call */
2065 if (ea_endpoint->ep_join_id) {
2066 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2067 memcpy(&message->param, param, sizeof(union parameter));
2068 message_put(message);
2072 /* port MESSAGE_CONNECT */
2073 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
2075 struct lcr_msg *message;
2077 unsigned int port_id = portlist->port_id;
2078 struct port_list *tportlist;
2082 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2084 /* signal to call tool */
2085 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
2087 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
2088 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2089 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
2090 tportlist = ea_endpoint->ep_portlist;
2091 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2092 tportlist = tportlist->next;
2093 if (tportlist->port_id == port_id)
2094 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2095 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2096 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
2097 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2098 message_put(message);
2099 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
2100 ea_endpoint->free_portlist(tportlist);
2102 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2107 if (e_callerinfo.interface[0])
2108 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface);
2110 /* screen connected name */
2112 SCPY(e_connectinfo.name, e_ext.name);
2114 /* add internal id to colp */
2115 SCPY(e_connectinfo.extension, e_ext.number);
2117 /* we store the connected port number */
2118 SCPY(e_extension_interface, e_connectinfo.interface);
2120 /* for internal and am calls, we get the extension's id */
2121 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
2122 SCPY(e_connectinfo.id, e_ext.callerid);
2123 SCPY(e_connectinfo.extension, e_ext.number);
2124 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2125 e_connectinfo.ntype = e_ext.callerid_type;
2126 e_connectinfo.present = e_ext.callerid_present;
2128 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2129 e_connectinfo.itype = INFO_ITYPE_VBOX;
2130 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2133 new_state(EPOINT_STATE_CONNECT);
2135 /* set volume of rx and tx */
2136 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2137 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2138 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2139 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2140 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2141 message_put(message);
2144 unsched_timer(&e_cfnr_timeout);
2145 unsched_timer(&e_cfnr_call_timeout);
2146 if (e_ext.number[0])
2147 e_dtmf = 1; /* allow dtmf */
2150 /* other calls with no caller id (or not available for the extension) and force colp */
2151 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2152 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2153 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
2154 /* external extension answered */
2155 port = find_port_id(portlist->port_id);
2157 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2158 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2163 /* send connect to join */
2164 if (ea_endpoint->ep_join_id) {
2165 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2166 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2167 message_put(message);
2169 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2170 message->param.audiopath = 1;
2171 message_put(message);
2172 } else if (!e_adminid) {
2174 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2175 SCPY(e_ext.number, e_cbcaller);
2176 new_state(EPOINT_STATE_IN_OVERLAP);
2177 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2179 /* get extension's info about terminal */
2180 if (!read_extension(&e_ext, e_ext.number)) {
2181 /* extension doesn't exist */
2182 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2183 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2184 new_state(EPOINT_STATE_OUT_DISCONNECT);
2185 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2189 /* put prefix in front of e_cbdialing */
2190 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2191 SCPY(e_dialinginfo.id, buffer);
2192 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2193 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2195 /* use caller id (or if exist: id_next_call) for this call */
2196 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2197 SCPY(e_callerinfo.extension, e_ext.number);
2198 if (e_ext.id_next_call_present >= 0) {
2199 SCPY(e_callerinfo.id, e_ext.id_next_call);
2200 e_callerinfo.present = e_ext.id_next_call_present;
2201 e_callerinfo.ntype = e_ext.id_next_call_type;
2202 e_ext.id_next_call_present = -1;
2203 /* extension is written */
2204 write_extension(&e_ext, e_ext.number);
2206 SCPY(e_callerinfo.id, e_ext.callerid);
2207 e_callerinfo.present = e_ext.callerid_present;
2208 e_callerinfo.ntype = e_ext.callerid_type;
2210 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2212 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2215 /* check if caller id is NOT authenticated */
2216 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2217 /* make call state to enter password */
2218 new_state(EPOINT_STATE_IN_OVERLAP);
2219 e_action = &action_password_write;
2220 unsched_timer(&e_match_timeout);
2221 e_match_to_action = NULL;
2222 e_dialinginfo.id[0] = '\0';
2223 e_extdialing = strchr(e_dialinginfo.id, '\0');
2224 schedule_timer(&e_password_timeout, 20, 0);
2227 /* incoming call (callback) */
2228 e_ruleset = ruleset_main;
2230 e_rule = e_ruleset->rule_first;
2232 e_extdialing = e_dialinginfo.id;
2233 if (e_dialinginfo.id[0]) {
2234 set_tone(portlist, "dialing");
2237 set_tone(portlist, "dialpbx");
2240 } else { /* testcall */
2241 set_tone(portlist, "hold");
2244 /* start recording if enabled, not when answering machine answers */
2245 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)) {
2246 /* check if we are a terminal */
2247 if (e_ext.number[0] == '\0')
2248 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2250 port = find_port_id(portlist->port_id);
2252 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2257 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2258 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2260 struct lcr_msg *message;
2262 unsigned int port_id = portlist->port_id;
2266 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2268 /* signal to call tool */
2269 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2271 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2272 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2273 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2278 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);
2279 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2280 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2282 /* check if we have more than one portlist relation and we just ignore the disconnect */
2283 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2284 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2285 portlist = ea_endpoint->ep_portlist;
2287 if (portlist->port_id == port_id)
2289 portlist = portlist->next;
2292 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2293 if (message_type != MESSAGE_RELEASE) {
2294 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2295 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2296 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2297 message_put(message);
2298 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2300 ea_endpoint->free_portlist(portlist);
2301 return; /* one relation removed */
2303 if (e_state == EPOINT_STATE_CONNECT) {
2304 /* use cause from port after connect */
2305 cause = param->disconnectinfo.cause;
2306 location = param->disconnectinfo.location;
2308 /* use multipoint cause if no connect yet */
2309 if (e_multipoint_cause) {
2310 cause = e_multipoint_cause;
2311 location = e_multipoint_location;
2313 cause = CAUSE_NOUSER;
2314 location = LOCATION_PRIVATE_LOCAL;
2318 unsched_timer(&e_cfnr_timeout);
2319 unsched_timer(&e_cfnr_call_timeout);
2321 /* process hangup */
2322 process_hangup(e_join_cause, e_join_location);
2323 e_multipoint_cause = 0;
2324 e_multipoint_location = 0;
2326 if (message_type == MESSAGE_DISCONNECT) {
2327 /* tone to disconnected end */
2328 SPRINT(buffer, "cause_%02x", cause);
2329 if (ea_endpoint->ep_portlist)
2330 set_tone(ea_endpoint->ep_portlist, buffer);
2332 new_state(EPOINT_STATE_IN_DISCONNECT);
2335 if (ea_endpoint->ep_join_id) {
2336 int haspatterns = 0;
2337 /* check if pattern is available */
2338 if (ea_endpoint->ep_portlist)
2339 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2340 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
2341 && message_type != MESSAGE_RELEASE) // if we release, we are done
2344 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2345 /* indicate patterns */
2346 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2347 message_put(message);
2348 /* connect audio, if not already */
2349 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2350 message->param.audiopath = 1;
2351 message_put(message);
2352 /* send disconnect */
2353 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2354 memcpy(&message->param, param, sizeof(union parameter));
2355 message_put(message);
2356 /* disable encryption if disconnected */
2357 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2359 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2362 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2365 if (message_type == MESSAGE_RELEASE)
2366 ea_endpoint->free_portlist(portlist);
2367 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2368 return; /* must exit here */
2371 /* port MESSAGE_TIMEOUT */
2372 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2376 trace_header("TIMEOUT", DIRECTION_IN);
2377 message_type = MESSAGE_DISCONNECT;
2378 switch (param->state) {
2379 case PORT_STATE_OUT_SETUP:
2380 case PORT_STATE_OUT_OVERLAP:
2381 add_trace("state", NULL, "outgoing setup/dialing");
2383 /* no user responding */
2384 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2385 return; /* must exit here */
2387 case PORT_STATE_IN_SETUP:
2388 case PORT_STATE_IN_OVERLAP:
2389 add_trace("state", NULL, "incoming setup/dialing");
2390 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2391 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2394 case PORT_STATE_OUT_PROCEEDING:
2395 add_trace("state", NULL, "outgoing proceeding");
2397 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2398 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2399 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2400 return; /* must exit here */
2402 case PORT_STATE_IN_PROCEEDING:
2403 add_trace("state", NULL, "incoming proceeding");
2404 param->disconnectinfo.cause = CAUSE_NOUSER;
2405 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2408 case PORT_STATE_OUT_ALERTING:
2409 add_trace("state", NULL, "outgoing alerting");
2411 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2412 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2413 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2414 return; /* must exit here */
2416 case PORT_STATE_CONNECT:
2417 add_trace("state", NULL, "connect");
2419 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2420 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2421 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2422 return; /* must exit here */
2424 case PORT_STATE_IN_ALERTING:
2425 add_trace("state", NULL, "incoming alerting");
2426 param->disconnectinfo.cause = CAUSE_NOANSWER;
2427 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2430 case PORT_STATE_IN_DISCONNECT:
2431 case PORT_STATE_OUT_DISCONNECT:
2432 add_trace("state", NULL, "disconnect");
2434 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2435 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2436 return; /* must exit here */
2439 param->disconnectinfo.cause = 31; /* normal unspecified */
2440 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2443 /* release call, disconnect isdn */
2445 new_state(EPOINT_STATE_OUT_DISCONNECT);
2446 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2447 SCPY(e_tone, cause);
2449 set_tone(portlist, cause);
2450 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2451 portlist = portlist->next;
2453 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2456 /* port MESSAGE_NOTIFY */
2457 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2459 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2461 struct lcr_msg *message;
2462 const char *logtext = "";
2465 /* signal to call tool */
2466 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);
2467 if (param->notifyinfo.notify) {
2468 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2471 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2472 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2473 case INFO_NOTIFY_REMOTE_HOLD:
2474 case INFO_NOTIFY_USER_SUSPENDED:
2475 /* tell call about it */
2476 if (ea_endpoint->ep_join_id) {
2477 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2478 message->param.audiopath = 0;
2479 message_put(message);
2483 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2484 case INFO_NOTIFY_USER_RESUMED:
2485 /* set volume of rx and tx */
2486 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2487 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2489 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2490 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2491 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2492 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2493 message_put(message);
2495 /* set current tone */
2497 set_tone(portlist, e_tone);
2498 /* tell call about it */
2499 if (ea_endpoint->ep_join_id) {
2500 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2501 message->param.audiopath = 1;
2502 message_put(message);
2507 /* get name of notify */
2508 switch(param->notifyinfo.notify) {
2513 logtext = "USER_SUSPENDED";
2516 logtext = "BEARER_SERVICE_CHANGED";
2519 logtext = "USER_RESUMED";
2522 logtext = "CONFERENCE_ESTABLISHED";
2525 logtext = "CONFERENCE_DISCONNECTED";
2528 logtext = "OTHER_PARTY_ADDED";
2531 logtext = "ISOLATED";
2534 logtext = "REATTACHED";
2537 logtext = "OTHER_PARTY_ISOLATED";
2540 logtext = "OTHER_PARTY_REATTACHED";
2543 logtext = "OTHER_PARTY_SPLIT";
2546 logtext = "OTHER_PARTY_DISCONNECTED";
2549 logtext = "CONFERENCE_FLOATING";
2552 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2555 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2558 logtext = "CALL_IS_A_WAITING_CALL";
2561 logtext = "DIVERSION_ACTIVATED";
2564 logtext = "RESERVED_CT_1";
2567 logtext = "RESERVED_CT_2";
2570 logtext = "REVERSE_CHARGING";
2573 logtext = "REMOTE_HOLD";
2576 logtext = "REMOTE_RETRIEVAL";
2579 logtext = "CALL_IS_DIVERTING";
2582 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2587 /* notify call if available */
2588 if (ea_endpoint->ep_join_id) {
2589 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2590 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2591 message_put(message);
2596 /* port MESSAGE_PROGRESS */
2597 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2599 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2601 struct lcr_msg *message;
2603 /* signal to call tool */
2604 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2606 /* send progress to call if available */
2607 if (ea_endpoint->ep_join_id) {
2608 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2609 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2610 message_put(message);
2615 /* port MESSAGE_FACILITY */
2616 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2618 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2620 struct lcr_msg *message;
2622 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2623 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2624 message_put(message);
2627 /* port MESSAGE_SUSPEND */
2628 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2629 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2631 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2633 /* epoint is now parked */
2634 ea_endpoint->ep_park = 1;
2635 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2636 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2638 /* remove port relation */
2639 ea_endpoint->free_portlist(portlist);
2642 /* port MESSAGE_RESUME */
2643 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2644 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2646 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2648 /* epoint is now resumed */
2649 ea_endpoint->ep_park = 0;
2653 /* port MESSAGE_ENABLEKEYPAD */
2654 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2656 struct lcr_msg *message;
2658 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2660 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2661 memcpy(&message->param, param, sizeof(union parameter));
2662 message_put(message);
2666 /* port sends message to the endpoint
2668 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2670 struct port_list *portlist;
2672 portlist = ea_endpoint->ep_portlist;
2674 if (port_id == portlist->port_id)
2676 portlist = portlist->next;
2679 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);
2683 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2684 switch(message_type) {
2685 case MESSAGE_TONE_EOF: /* tone is end of file */
2686 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2688 if (e_action->index == ACTION_VBOX_PLAY) {
2691 if (e_action->index == ACTION_EFI) {
2697 case MESSAGE_TONE_COUNTER: /* counter info received */
2698 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);
2700 if (e_action->index == ACTION_VBOX_PLAY) {
2701 e_vbox_counter = param->counter.current;
2702 if (param->counter.max >= 0)
2703 e_vbox_counter_max = param->counter.max;
2707 /* PORT sends SETUP message */
2709 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);
2710 if (e_state!=EPOINT_STATE_IDLE) {
2711 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2714 port_setup(portlist, message_type, param);
2717 /* PORT sends INFORMATION message */
2718 case MESSAGE_INFORMATION: /* additional digits received */
2719 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);
2720 port_information(portlist, message_type, param);
2723 /* PORT sends FACILITY message */
2724 case MESSAGE_FACILITY:
2725 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2726 port_facility(portlist, message_type, param);
2729 /* PORT sends DTMF message */
2730 case MESSAGE_DTMF: /* dtmf digits received */
2731 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);
2732 port_dtmf(portlist, message_type, param);
2735 /* PORT sends CRYPT message */
2736 case MESSAGE_CRYPT: /* crypt response received */
2737 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2738 port_crypt(portlist, message_type, param);
2741 /* PORT sends MORE message */
2742 case MESSAGE_OVERLAP:
2743 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);
2744 if (e_state != EPOINT_STATE_OUT_SETUP) {
2745 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);
2748 port_overlap(portlist, message_type, param);
2751 /* PORT sends PROCEEDING message */
2752 case MESSAGE_PROCEEDING: /* port is proceeding */
2753 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);
2754 if (e_state!=EPOINT_STATE_OUT_SETUP
2755 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2756 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);
2759 port_proceeding(portlist, message_type, param);
2762 /* PORT sends ALERTING message */
2763 case MESSAGE_ALERTING:
2764 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);
2765 if (e_state!=EPOINT_STATE_OUT_SETUP
2766 && e_state!=EPOINT_STATE_OUT_OVERLAP
2767 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2768 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);
2771 port_alerting(portlist, message_type, param);
2774 /* PORT sends CONNECT message */
2775 case MESSAGE_CONNECT:
2776 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);
2777 if (e_state!=EPOINT_STATE_OUT_SETUP
2778 && e_state!=EPOINT_STATE_OUT_OVERLAP
2779 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2780 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2781 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2784 port_connect(portlist, message_type, param);
2787 /* PORT sends DISCONNECT message */
2788 case MESSAGE_DISCONNECT: /* port is disconnected */
2789 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);
2790 port_disconnect_release(portlist, message_type, param);
2793 /* PORT sends a RELEASE message */
2794 case MESSAGE_RELEASE: /* port releases */
2795 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);
2796 /* portlist is release at port_disconnect_release, thanx Paul */
2797 port_disconnect_release(portlist, message_type, param);
2800 /* PORT sends a TIMEOUT message */
2801 case MESSAGE_TIMEOUT:
2802 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);
2803 port_timeout(portlist, message_type, param);
2804 break; /* release */
2806 /* PORT sends a NOTIFY message */
2807 case MESSAGE_NOTIFY:
2808 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);
2809 port_notify(portlist, message_type, param);
2812 /* PORT sends a PROGRESS message */
2813 case MESSAGE_PROGRESS:
2814 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);
2815 port_progress(portlist, message_type, param);
2818 /* PORT sends a SUSPEND message */
2819 case MESSAGE_SUSPEND:
2820 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);
2821 port_suspend(portlist, message_type, param);
2822 break; /* suspend */
2824 /* PORT sends a RESUME message */
2825 case MESSAGE_RESUME:
2826 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);
2827 port_resume(portlist, message_type, param);
2831 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2832 /* port assigns bchannel */
2833 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2834 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);
2835 /* only one port is expected to be connected to bchannel */
2836 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2837 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2841 /* PORT requests DTMF */
2842 case MESSAGE_ENABLEKEYPAD:
2843 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') requests DTMF/KEYPAD.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2844 port_enablekeypad(portlist, message_type, param);
2849 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);
2852 /* Note: this endpoint may be destroyed, so we MUST return */
2856 /* messages from join
2858 /* join MESSAGE_CRYPT */
2859 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2861 switch(param->crypt.type) {
2862 /* message from remote port to "crypt manager" */
2863 case CU_ACTK_REQ: /* activate key-exchange */
2864 case CU_ACTS_REQ: /* activate shared key */
2865 case CU_DACT_REQ: /* deactivate */
2866 case CU_INFO_REQ: /* request last info message */
2867 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2870 /* message from "crypt manager" to user */
2871 case CU_ACTK_CONF: /* key-echange done */
2872 case CU_ACTS_CONF: /* shared key done */
2873 case CU_DACT_CONF: /* deactivated */
2874 case CU_DACT_IND: /* deactivated */
2875 case CU_ERROR_IND: /* receive error message */
2876 case CU_INFO_IND: /* receive info message */
2877 case CU_INFO_CONF: /* receive info message */
2878 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2882 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);
2886 /* join MESSAGE_INFORMATION */
2887 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2889 struct lcr_msg *message;
2894 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2895 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2896 message_put(message);
2897 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2898 portlist = portlist->next;
2902 /* join MESSAGE_FACILITY */
2903 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2905 struct lcr_msg *message;
2907 if (!e_ext.facility && e_ext.number[0]) {
2912 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2913 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2914 message_put(message);
2915 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2916 portlist = portlist->next;
2920 /* join MESSAGE_MORE */
2921 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2923 struct lcr_msg *message;
2925 new_state(EPOINT_STATE_IN_OVERLAP);
2928 if (e_join_pattern && e_ext.own_setup) {
2929 /* disconnect audio */
2930 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2931 message->param.audiopath = 0;
2932 message_put(message);
2934 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2935 if (e_dialinginfo.id[0])
2936 set_tone(portlist, "dialing");
2938 set_tone(portlist, "dialtone");
2941 if (e_dialinginfo.id[0]) {
2942 set_tone(portlist, "dialing");
2944 if (e_ext.number[0])
2945 set_tone(portlist, "dialpbx");
2947 set_tone(portlist, "dialtone");
2951 /* join MESSAGE_PROCEEDING */
2952 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2954 struct lcr_msg *message;
2956 new_state(EPOINT_STATE_IN_PROCEEDING);
2958 /* own proceeding tone */
2959 if (e_join_pattern) {
2960 /* connect / disconnect audio */
2961 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2962 if (e_ext.own_proceeding)
2963 message->param.audiopath = 0;
2965 message->param.audiopath = 1;
2966 message_put(message);
2968 // UCPY(e_join_tone, "proceeding");
2970 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2971 message_put(message);
2972 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2974 set_tone(portlist, "proceeding");
2977 /* join MESSAGE_ALERTING */
2978 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2980 struct lcr_msg *message;
2982 new_state(EPOINT_STATE_IN_ALERTING);
2984 /* own alerting tone */
2985 if (e_join_pattern) {
2986 /* connect / disconnect audio */
2987 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2988 if (e_ext.own_alerting)
2989 message->param.audiopath = 0;
2991 message->param.audiopath = 1;
2992 message_put(message);
2995 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2996 message_put(message);
2997 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2999 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
3000 set_tone(portlist, "ringing");
3003 if (e_ext.number[0])
3004 set_tone(portlist, "ringpbx");
3006 set_tone(portlist, "ringing");
3008 if (e_ext.number[0])
3009 e_dtmf = 1; /* allow dtmf */
3012 /* join MESSAGE_CONNECT */
3013 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
3015 struct lcr_msg *message;
3018 new_state(EPOINT_STATE_CONNECT);
3019 // UCPY(e_join_tone, "");
3021 if (e_ext.number[0])
3022 e_dtmf = 1; /* allow dtmf */
3025 unsched_timer(&e_powerdial_timeout);
3026 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
3028 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3029 memcpy(&message->param, param, sizeof(union parameter));
3031 /* screen clip if prefix is required */
3032 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
3033 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
3034 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
3035 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3038 /* use internal caller id */
3039 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
3040 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
3041 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3044 /* handle restricted caller ids */
3045 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);
3046 /* display callerid if desired for extension */
3047 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));
3049 /* use conp, if enabld */
3050 // if (!e_ext.centrex)
3051 // message->param.connectinfo.name[0] = '\0';
3054 message_put(message);
3055 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3057 set_tone(portlist, NULL);
3059 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3060 message->param.audiopath = 1;
3061 message_put(message);
3066 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3067 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3070 struct lcr_msg *message;
3071 struct port_list *portlist = NULL;
3075 /* be sure that we are active */
3077 e_tx_state = NOTIFY_STATE_ACTIVE;
3079 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
3080 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
3081 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
3083 /* set time for power dialing */
3084 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
3087 /* set redial tone */
3088 if (ea_endpoint->ep_portlist) {
3091 set_tone(ea_endpoint->ep_portlist, "redial");
3092 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);
3093 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3094 if (e_state==EPOINT_STATE_IN_OVERLAP) {
3095 new_state(EPOINT_STATE_IN_PROCEEDING);
3096 if (ea_endpoint->ep_portlist) {
3097 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3098 message_put(message);
3099 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3101 /* caused the error, that the first knock sound was not there */
3102 /* set_tone(portlist, "proceeding"); */
3104 /* send display of powerdialing */
3105 if (e_ext.display_dialing) {
3106 portlist = ea_endpoint->ep_portlist;
3108 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3110 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3112 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3113 message_put(message);
3114 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3115 portlist = portlist->next;
3125 if ((e_state!=EPOINT_STATE_CONNECT
3126 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3127 && e_state!=EPOINT_STATE_IN_OVERLAP
3128 && e_state!=EPOINT_STATE_IN_PROCEEDING
3129 && e_state!=EPOINT_STATE_IN_ALERTING)
3130 || !ea_endpoint->ep_portlist) { /* or no port */
3131 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3132 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3133 return; /* must exit here */
3136 if (!e_join_cause) {
3137 e_join_cause = param->disconnectinfo.cause;
3138 e_join_location = param->disconnectinfo.location;
3141 /* on release we need the audio again! */
3142 if (message_type == MESSAGE_RELEASE) {
3144 ea_endpoint->ep_join_id = 0;
3146 /* disconnect and select tone */
3147 new_state(EPOINT_STATE_OUT_DISCONNECT);
3148 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3149 /* if own_cause, we must release the join */
3150 if (e_ext.own_cause /* own cause */
3151 || !e_join_pattern) { /* no patterns */
3152 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);
3153 if (message_type != MESSAGE_RELEASE)
3154 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3156 } else { /* else we enable audio */
3157 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3158 message->param.audiopath = 1;
3159 message_put(message);
3161 /* send disconnect message */
3162 SCPY(e_tone, cause);
3163 portlist = ea_endpoint->ep_portlist;
3165 set_tone(portlist, cause);
3166 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3167 portlist = portlist->next;
3171 /* join MESSAGE_SETUP */
3172 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3174 struct lcr_msg *message;
3175 // struct interface *interface;
3177 /* if we already in setup state, we just update the dialing with new digits */
3178 if (e_state == EPOINT_STATE_OUT_SETUP
3179 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3180 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3181 /* if digits changed, what we have already dialed */
3182 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3183 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);
3184 /* release all ports */
3185 while((portlist = ea_endpoint->ep_portlist)) {
3186 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3187 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3188 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3189 message_put(message);
3190 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3191 ea_endpoint->free_portlist(portlist);
3194 /* disconnect audio */
3195 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3196 message->param.audiopath = 0;
3197 message_put(message);
3199 /* get dialing info */
3200 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3201 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3202 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3203 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3204 new_state(EPOINT_STATE_OUT_OVERLAP);
3207 schedule_timer(&e_redial_timeout, 1, 0);
3210 /* if we have a pending redial, so we just adjust the dialing number */
3211 if (e_redial_timeout.active) {
3212 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);
3213 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3216 if (!ea_endpoint->ep_portlist) {
3217 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3219 if (ea_endpoint->ep_portlist->next) {
3220 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3222 if (e_state == EPOINT_STATE_OUT_SETUP) {
3224 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);
3225 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3228 /* get what we have not dialed yet */
3229 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));
3230 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3231 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3232 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3233 message_put(message);
3234 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3236 /* always store what we have dialed or queued */
3237 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3241 if (e_state != EPOINT_STATE_IDLE) {
3242 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3245 /* if an internal extension is dialed, copy that number */
3246 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3247 SCPY(e_ext.number, param->setup.dialinginfo.id);
3248 /* if an internal extension is dialed, get extension's info about caller */
3249 if (e_ext.number[0]) {
3250 if (!read_extension(&e_ext, e_ext.number)) {
3251 e_ext.number[0] = '\0';
3252 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3256 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3257 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3258 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3259 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3260 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3262 /* process (voice over) data calls */
3263 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3264 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3265 memset(&e_capainfo, 0, sizeof(e_capainfo));
3266 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3267 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3268 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3271 new_state(EPOINT_STATE_OUT_SETUP);
3272 /* call special setup routine */
3276 /* join MESSAGE_mISDNSIGNAL */
3277 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3279 struct lcr_msg *message;
3282 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3283 memcpy(&message->param, param, sizeof(union parameter));
3284 message_put(message);
3285 portlist = portlist->next;
3289 /* join MESSAGE_BRIDE */
3290 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3292 struct lcr_msg *message;
3295 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3296 memcpy(&message->param, param, sizeof(union parameter));
3297 message_put(message);
3298 portlist = portlist->next;
3302 /* join MESSAGE_NOTIFY */
3303 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3305 struct lcr_msg *message;
3308 if (param->notifyinfo.notify) {
3309 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3310 // /* if notification was generated locally, we turn hold music on/off */
3311 // if (param->notifyinfo.local)
3312 // 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)
3316 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3317 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3319 set_tone(portlist, "");
3320 portlist = portlist->next;
3323 portlist = ea_endpoint->ep_portlist;
3328 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3330 set_tone(portlist, "hold");
3331 portlist = portlist->next;
3333 portlist = ea_endpoint->ep_portlist;
3338 /* save new state */
3339 e_tx_state = new_state;
3342 /* notify port(s) about it */
3344 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3345 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3346 /* handle restricted caller ids */
3347 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3348 /* display callerid if desired for extension */
3349 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));
3350 message_put(message);
3351 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3352 portlist = portlist->next;
3356 /* join MESSAGE_DTMF */
3357 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3359 struct lcr_msg *message;
3362 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3363 memcpy(&message->param, param, sizeof(union parameter));
3364 message_put(message);
3365 portlist = portlist->next;
3369 /* JOIN sends messages to the endpoint
3371 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3373 struct port_list *portlist;
3374 struct lcr_msg *message;
3377 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3381 portlist = ea_endpoint->ep_portlist;
3383 // 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);
3384 switch(message_type) {
3385 /* JOIN SENDS TONE message */
3387 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);
3388 set_tone(portlist, param->tone.name);
3391 /* JOIN SENDS CRYPT message */
3393 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);
3394 join_crypt(portlist, message_type, param);
3397 /* JOIN sends INFORMATION message */
3398 case MESSAGE_INFORMATION:
3399 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);
3400 join_information(portlist, message_type, param);
3403 /* JOIN sends FACILITY message */
3404 case MESSAGE_FACILITY:
3405 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);
3406 join_facility(portlist, message_type, param);
3409 /* JOIN sends OVERLAP message */
3410 case MESSAGE_OVERLAP:
3411 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);
3412 if (e_state!=EPOINT_STATE_IN_SETUP
3413 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3414 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3417 join_overlap(portlist, message_type, param);
3420 /* JOIN sends PROCEEDING message */
3421 case MESSAGE_PROCEEDING:
3422 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);
3423 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3424 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3427 join_proceeding(portlist, message_type, param);
3430 /* JOIN sends ALERTING message */
3431 case MESSAGE_ALERTING:
3432 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);
3433 if (e_state!=EPOINT_STATE_IN_OVERLAP
3434 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3435 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3438 join_alerting(portlist, message_type, param);
3441 /* JOIN sends CONNECT message */
3442 case MESSAGE_CONNECT:
3443 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);
3444 if (e_state!=EPOINT_STATE_IN_OVERLAP
3445 && e_state!=EPOINT_STATE_IN_PROCEEDING
3446 && e_state!=EPOINT_STATE_IN_ALERTING) {
3447 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3450 join_connect(portlist, message_type, param);
3453 /* JOIN sends DISCONNECT/RELEASE message */
3454 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3455 case MESSAGE_RELEASE: /* JOIN releases */
3456 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);
3457 join_disconnect_release(message_type, param);
3460 /* JOIN sends SETUP message */
3462 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);
3463 join_setup(portlist, message_type, param);
3466 /* JOIN sends special mISDNSIGNAL message */
3467 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3468 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);
3469 join_mISDNsignal(portlist, message_type, param);
3472 /* JOIN sends bridge message */
3473 case MESSAGE_BRIDGE: /* bride message to port */
3474 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bridge message.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3475 join_bridge(portlist, message_type, param);
3478 /* JOIN has pattern available */
3479 case MESSAGE_PATTERN: /* indicating pattern available */
3480 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);
3481 if (!e_join_pattern) {
3482 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3486 set_tone(portlist, NULL);
3487 portlist = portlist->next;
3489 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3490 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3491 message->param.audiopath = 1;
3492 message_put(message);
3496 /* JOIN has no pattern available */
3497 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3498 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);
3499 if (e_join_pattern) {
3500 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3502 /* disconnect our audio tx and rx */
3503 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3504 message->param.audiopath = 0;
3505 message_put(message);
3510 /* JOIN (dunno at the moment) */
3511 case MESSAGE_REMOTE_AUDIO:
3512 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);
3513 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3514 message->param.audiopath = param->channel;
3515 message_put(message);
3519 /* JOIN sends a notify message */
3520 case MESSAGE_NOTIFY:
3521 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);
3522 join_notify(portlist, message_type, param);
3525 /* JOIN wants keypad / dtmf */
3526 case MESSAGE_ENABLEKEYPAD:
3527 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);
3530 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3534 /* JOIN sends a DTMF message */
3536 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received dtmf.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3537 join_dtmf(portlist, message_type, param);
3541 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);
3546 /* pick_join will connect the first incoming call found. the endpoint
3547 * will receivce a MESSAGE_CONNECT.
3549 int match_list(char *list, char *item)
3551 char *end, *next = NULL;
3553 /* no list make matching */
3558 /* eliminate white spaces */
3559 while (*list > '\0' && *list <= ' ')
3565 /* if end of list is reached, we return */
3566 if (list[0] == '\0')
3568 /* if we have more than one entry (left) */
3569 if ((end = strchr(list, ',')))
3572 next = end = strchr(list, '\0');
3573 while (*(end-1) <= ' ')
3575 /* if string part matches item */
3576 if (!strncmp(list, item, end-list))
3582 void EndpointAppPBX::pick_join(char *extensions)
3584 struct lcr_msg *message;
3585 struct port_list *portlist;
3587 class EndpointAppPBX *eapp, *found;
3589 class JoinPBX *joinpbx;
3590 struct join_relation *relation;
3593 /* find an endpoint that is ringing internally or vbox with higher priority */
3596 eapp = apppbx_first;
3598 if (eapp!=this && ea_endpoint->ep_portlist) {
3599 portlist = eapp->ea_endpoint->ep_portlist;
3601 if ((port = find_port_id(portlist->port_id))) {
3602 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3603 if (match_list(extensions, eapp->e_ext.number)) {
3609 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3610 && port->p_state==PORT_STATE_OUT_ALERTING)
3611 if (match_list(extensions, eapp->e_ext.number)) {
3615 portlist = portlist->next;
3623 /* if no endpoint found */
3625 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);
3627 set_tone(ea_endpoint->ep_portlist, "cause_10");
3628 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3629 new_state(EPOINT_STATE_OUT_DISCONNECT);
3634 if (ea_endpoint->ep_join_id) {
3635 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3638 if (!eapp->ea_endpoint->ep_join_id) {
3639 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3642 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3644 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3647 if (join->j_type != JOIN_TYPE_PBX) {
3648 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3651 joinpbx = (class JoinPBX *)join;
3652 relation = joinpbx->j_relation;
3654 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3657 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3658 relation = relation->next;
3660 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3665 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3667 if (options.deb & DEBUG_EPOINT) {
3668 class Join *debug_c = join_first;
3669 class Endpoint *debug_e = epoint_first;
3670 class Port *debug_p = port_first;
3672 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3674 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3676 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3677 debug_c = debug_c->next;
3679 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3681 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3682 debug_e = debug_e->next;
3684 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3686 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3687 debug_p = debug_p->next;
3692 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3693 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3694 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3696 /* connnecting our endpoint */
3697 new_state(EPOINT_STATE_CONNECT);
3698 if (e_ext.number[0])
3700 set_tone(ea_endpoint->ep_portlist, NULL);
3702 /* now we send a release to the ringing endpoint */
3703 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3704 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3705 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3706 message_put(message);
3708 /* we send a connect to the join with our caller id */
3709 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3710 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3711 message->param.connectinfo.present = e_callerinfo.present;
3712 message->param.connectinfo.screen = e_callerinfo.screen;
3713 message->param.connectinfo.itype = e_callerinfo.itype;
3714 message->param.connectinfo.ntype = e_callerinfo.ntype;
3715 message_put(message);
3717 /* we send a connect to our port with the remote callerid */
3718 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3719 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3720 message->param.connectinfo.present = eapp->e_callerinfo.present;
3721 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3722 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3723 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3724 /* handle restricted caller ids */
3725 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);
3726 /* display callerid if desired for extension */
3727 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));
3728 message_put(message);
3730 /* we send a connect to the audio path (not for vbox) */
3731 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3732 message->param.audiopath = 1;
3733 message_put(message);
3735 /* beeing paranoid, we make call update */
3736 trigger_work(&joinpbx->j_updatebridge);
3738 if (options.deb & DEBUG_EPOINT) {
3739 class Join *debug_c = join_first;
3740 class Endpoint *debug_e = epoint_first;
3741 class Port *debug_p = port_first;
3743 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3745 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3747 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3748 debug_c = debug_c->next;
3750 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3752 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3753 debug_e = debug_e->next;
3755 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3757 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3758 debug_p = debug_p->next;
3764 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3766 void EndpointAppPBX::join_join(void)
3768 struct lcr_msg *message;
3769 struct join_relation *our_relation, *other_relation;
3770 struct join_relation **our_relation_pointer, **other_relation_pointer;
3771 class Join *our_join, *other_join;
3772 class JoinPBX *our_joinpbx, *other_joinpbx;
3773 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3774 class Port *our_port, *other_port;
3775 class Pdss1 *our_pdss1, *other_pdss1;
3777 /* are we a candidate to join a join? */
3778 our_join = find_join_id(ea_endpoint->ep_join_id);
3780 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3783 if (our_join->j_type != JOIN_TYPE_PBX) {
3784 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3787 our_joinpbx = (class JoinPBX *)our_join;
3788 if (!ea_endpoint->ep_portlist) {
3789 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3792 if (!e_ext.number[0]) {
3793 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3796 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3798 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3801 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3802 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3805 our_pdss1 = (class Pdss1 *)our_port;
3807 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3808 other_eapp = apppbx_first;
3810 if (other_eapp == this) {
3811 other_eapp = other_eapp->next;
3814 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);
3815 if (other_eapp->e_ext.number[0] /* has terminal */
3816 && other_eapp->ea_endpoint->ep_portlist /* has port */
3817 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3818 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3819 if (other_port) { /* port still exists */
3820 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3821 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3822 other_pdss1 = (class Pdss1 *)other_port;
3823 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);
3824 if (other_pdss1->p_m_hold /* port is on hold */
3825 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3826 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3829 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3832 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3835 other_eapp = other_eapp->next;
3838 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3841 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3843 /* if we have the same join */
3844 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3845 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3848 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3850 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3853 if (other_join->j_type != JOIN_TYPE_PBX) {
3854 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3857 other_joinpbx = (class JoinPBX *)other_join;
3858 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3859 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3863 /* remove relation to endpoint for join on hold */
3864 other_relation = other_joinpbx->j_relation;
3865 other_relation_pointer = &other_joinpbx->j_relation;
3866 while(other_relation) {
3867 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3868 /* detach other endpoint on hold */
3869 *other_relation_pointer = other_relation->next;
3870 FREE(other_relation, sizeof(struct join_relation));
3872 other_relation = *other_relation_pointer;
3873 other_eapp->ea_endpoint->ep_join_id = 0;
3877 /* change join/hold pointer of endpoint to the new join */
3878 temp_epoint = find_epoint_id(other_relation->epoint_id);
3880 if (temp_epoint->ep_join_id == other_join->j_serial)
3881 temp_epoint->ep_join_id = our_join->j_serial;
3884 other_relation_pointer = &other_relation->next;
3885 other_relation = other_relation->next;
3887 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3889 /* join call relations */
3890 our_relation = our_joinpbx->j_relation;
3891 our_relation_pointer = &our_joinpbx->j_relation;
3892 while(our_relation) {
3893 our_relation_pointer = &our_relation->next;
3894 our_relation = our_relation->next;
3896 *our_relation_pointer = other_joinpbx->j_relation;
3897 other_joinpbx->j_relation = NULL;
3898 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3900 /* release endpoint on hold */
3901 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3902 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3903 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3904 message_put(message);
3906 /* if we are not a partyline, we get partyline state from other join */
3907 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3909 /* remove empty join */
3911 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3913 /* mixer must update */
3914 trigger_work(&our_joinpbx->j_updatebridge);
3916 /* we send a retrieve to that endpoint */
3917 // mixer will update the hold-state of the join and send it to the endpoints is changes
3921 /* check if we have an external call
3922 * this is used to check for encryption ability
3924 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3926 struct join_relation *relation;
3928 class JoinPBX *joinpbx;
3929 class Endpoint *epoint;
3931 /* some paranoia check */
3932 if (!ea_endpoint->ep_portlist) {
3933 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3934 *errstr = "No Call";
3937 if (!e_ext.number[0]) {
3938 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3939 *errstr = "No Call";
3943 /* check if we have a join with 2 parties */
3944 join = find_join_id(ea_endpoint->ep_join_id);
3946 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3947 *errstr = "No Call";
3950 if (join->j_type != JOIN_TYPE_PBX) {
3951 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3952 *errstr = "No PBX Call";
3955 joinpbx = (class JoinPBX *)join;
3956 relation = joinpbx->j_relation;
3958 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3959 *errstr = "No Call";
3962 if (!relation->next) {
3963 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3964 *errstr = "No Call";
3967 if (relation->next->next) {
3968 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3969 *errstr = "Err: Conference";
3972 if (relation->epoint_id == ea_endpoint->ep_serial) {
3973 relation = relation->next;
3974 if (relation->epoint_id == ea_endpoint->ep_serial) {
3975 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3976 *errstr = "Software Error";
3981 /* check remote port for external call */
3982 epoint = find_epoint_id(relation->epoint_id);
3984 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3985 *errstr = "No Call";
3988 if (!epoint->ep_portlist) {
3989 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3990 *errstr = "No Call";
3993 *port = find_port_id(epoint->ep_portlist->port_id);
3995 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
3996 *errstr = "No Call";
3999 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4000 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4001 *errstr = "No Ext Call";
4004 if ((*port)->p_state != PORT_STATE_CONNECT) {
4005 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4006 *errstr = "No Ext Connect";
4012 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4014 const char *logtext = "unknown";
4017 switch(message_type) {
4019 trace_header("SETUP", dir);
4020 if (dir == DIRECTION_OUT)
4021 add_trace("to", NULL, "CH(%lu)", port_id);
4022 if (dir == DIRECTION_IN)
4023 add_trace("from", NULL, "CH(%lu)", port_id);
4024 if (param->setup.callerinfo.extension[0])
4025 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4026 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4027 switch(param->setup.callerinfo.present) {
4028 case INFO_PRESENT_RESTRICTED:
4029 add_trace("caller id", "present", "restricted");
4031 case INFO_PRESENT_ALLOWED:
4032 add_trace("caller id", "present", "allowed");
4035 add_trace("caller id", "present", "not available");
4037 if (param->setup.callerinfo.ntype2) {
4038 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4039 switch(param->setup.callerinfo.present) {
4040 case INFO_PRESENT_RESTRICTED:
4041 add_trace("caller id2", "present", "restricted");
4043 case INFO_PRESENT_ALLOWED:
4044 add_trace("caller id2", "present", "allowed");
4047 add_trace("caller id2", "present", "not available");
4050 if (param->setup.redirinfo.id[0]) {
4051 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4052 switch(param->setup.redirinfo.present) {
4053 case INFO_PRESENT_RESTRICTED:
4054 add_trace("redir'ing", "present", "restricted");
4056 case INFO_PRESENT_ALLOWED:
4057 add_trace("redir'ing", "present", "allowed");
4060 add_trace("redir'ing", "present", "not available");
4063 if (param->setup.dialinginfo.id[0])
4064 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4065 if (param->setup.dialinginfo.keypad[0])
4066 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4067 if (param->setup.dialinginfo.display[0])
4068 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4069 if (param->setup.dialinginfo.sending_complete)
4070 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4074 case MESSAGE_OVERLAP:
4075 trace_header("SETUP ACKNOWLEDGE", dir);
4076 if (dir == DIRECTION_OUT)
4077 add_trace("to", NULL, "CH(%lu)", port_id);
4078 if (dir == DIRECTION_IN)
4079 add_trace("from", NULL, "CH(%lu)", port_id);
4083 case MESSAGE_PROCEEDING:
4084 trace_header("PROCEEDING", dir);
4085 if (dir == DIRECTION_OUT)
4086 add_trace("to", NULL, "CH(%lu)", port_id);
4087 if (dir == DIRECTION_IN)
4088 add_trace("from", NULL, "CH(%lu)", port_id);
4092 case MESSAGE_ALERTING:
4093 trace_header("ALERTING", dir);
4094 if (dir == DIRECTION_OUT)
4095 add_trace("to", NULL, "CH(%lu)", port_id);
4096 if (dir == DIRECTION_IN)
4097 add_trace("from", NULL, "CH(%lu)", port_id);
4101 case MESSAGE_CONNECT:
4102 trace_header("CONNECT", dir);
4103 if (dir == DIRECTION_OUT)
4104 add_trace("to", NULL, "CH(%lu)", port_id);
4105 if (dir == DIRECTION_IN)
4106 add_trace("from", NULL, "CH(%lu)", port_id);
4107 if (param->connectinfo.extension[0])
4108 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4109 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4110 switch(param->connectinfo.present) {
4111 case INFO_PRESENT_RESTRICTED:
4112 add_trace("connect id", "present", "restricted");
4114 case INFO_PRESENT_ALLOWED:
4115 add_trace("connect id", "present", "allowed");
4118 add_trace("connect id", "present", "not available");
4120 if (param->connectinfo.display[0])
4121 add_trace("display", NULL, "%s", param->connectinfo.display);
4125 case MESSAGE_DISCONNECT:
4126 case MESSAGE_RELEASE:
4127 if (message_type == MESSAGE_DISCONNECT)
4128 trace_header("DISCONNECT", dir);
4130 trace_header("RELEASE", dir);
4131 if (dir == DIRECTION_OUT)
4132 add_trace("to", NULL, "CH(%lu)", port_id);
4133 if (dir == DIRECTION_IN)
4134 add_trace("from", NULL, "CH(%lu)", port_id);
4135 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4136 switch(param->disconnectinfo.location) {
4138 add_trace("cause", "location", "0-User");
4140 case LOCATION_PRIVATE_LOCAL:
4141 add_trace("cause", "location", "1-Local-PBX");
4143 case LOCATION_PUBLIC_LOCAL:
4144 add_trace("cause", "location", "2-Local-Exchange");
4146 case LOCATION_TRANSIT:
4147 add_trace("cause", "location", "3-Transit");
4149 case LOCATION_PUBLIC_REMOTE:
4150 add_trace("cause", "location", "4-Remote-Exchange");
4152 case LOCATION_PRIVATE_REMOTE:
4153 add_trace("cause", "location", "5-Remote-PBX");
4155 case LOCATION_INTERNATIONAL:
4156 add_trace("cause", "location", "7-International-Exchange");
4158 case LOCATION_BEYOND:
4159 add_trace("cause", "location", "10-Beyond-Interworking");
4162 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4164 if (param->disconnectinfo.display[0])
4165 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4169 case MESSAGE_NOTIFY:
4170 switch(param->notifyinfo.notify) {
4175 logtext = "USER_SUSPENDED";
4178 logtext = "BEARER_SERVICE_CHANGED";
4181 logtext = "USER_RESUMED";
4184 logtext = "CONFERENCE_ESTABLISHED";
4187 logtext = "CONFERENCE_DISCONNECTED";
4190 logtext = "OTHER_PARTY_ADDED";
4193 logtext = "ISOLATED";
4196 logtext = "REATTACHED";
4199 logtext = "OTHER_PARTY_ISOLATED";
4202 logtext = "OTHER_PARTY_REATTACHED";
4205 logtext = "OTHER_PARTY_SPLIT";
4208 logtext = "OTHER_PARTY_DISCONNECTED";
4211 logtext = "CONFERENCE_FLOATING";
4214 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4217 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4220 logtext = "CALL_IS_A_WAITING_CALL";
4223 logtext = "DIVERSION_ACTIVATED";
4226 logtext = "RESERVED_CT_1";
4229 logtext = "RESERVED_CT_2";
4232 logtext = "REVERSE_CHARGING";
4235 logtext = "REMOTE_HOLD";
4238 logtext = "REMOTE_RETRIEVAL";
4241 logtext = "CALL_IS_DIVERTING";
4244 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4248 trace_header("NOTIFY", dir);
4249 if (dir == DIRECTION_OUT)
4250 add_trace("to", NULL, "CH(%lu)", port_id);
4251 if (dir == DIRECTION_IN)
4252 add_trace("from", NULL, "CH(%lu)", port_id);
4253 if (param->notifyinfo.notify)
4254 add_trace("indicator", NULL, "%s", logtext);
4255 if (param->notifyinfo.id[0]) {
4256 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4257 switch(param->notifyinfo.present) {
4258 case INFO_PRESENT_RESTRICTED:
4259 add_trace("redir'on", "present", "restricted");
4261 case INFO_PRESENT_ALLOWED:
4262 add_trace("redir'on", "present", "allowed");
4265 add_trace("redir'on", "present", "not available");
4268 if (param->notifyinfo.display[0])
4269 add_trace("display", NULL, "%s", param->notifyinfo.display);
4273 case MESSAGE_PROGRESS:
4274 switch(param->progressinfo.progress) {
4276 logtext = "Call is not end to end ISDN";
4279 logtext = "Destination address is non-ISDN";
4282 logtext = "Origination address is non-ISDN";
4285 logtext = "Call has returned to the ISDN";
4288 logtext = "In-band info or pattern available";
4291 SPRINT(buffer, "%d", param->progressinfo.progress);
4295 trace_header("PROGRESS", dir);
4296 if (dir == DIRECTION_OUT)
4297 add_trace("to", NULL, "CH(%lu)", port_id);
4298 if (dir == DIRECTION_IN)
4299 add_trace("from", NULL, "CH(%lu)", port_id);
4300 add_trace("indicator", NULL, "%s", logtext);
4301 switch(param->progressinfo.location) {
4303 add_trace("cause", "location", "0-User");
4305 case LOCATION_PRIVATE_LOCAL:
4306 add_trace("cause", "location", "1-Local-PBX");
4308 case LOCATION_PUBLIC_LOCAL:
4309 add_trace("cause", "location", "2-Local-Exchange");
4311 case LOCATION_TRANSIT:
4312 add_trace("cause", "location", "3-Transit");
4314 case LOCATION_PUBLIC_REMOTE:
4315 add_trace("cause", "location", "4-Remote-Exchange");
4317 case LOCATION_PRIVATE_REMOTE:
4318 add_trace("cause", "location", "5-Remote-PBX");
4320 case LOCATION_INTERNATIONAL:
4321 add_trace("cause", "location", "7-International-Exchange");
4323 case LOCATION_BEYOND:
4324 add_trace("cause", "location", "10-Beyond-Interworking");
4327 add_trace("cause", "location", "%d", param->progressinfo.location);
4332 case MESSAGE_INFORMATION:
4333 trace_header("INFORMATION", dir);
4334 if (dir == DIRECTION_OUT)
4335 add_trace("to", NULL, "CH(%lu)", port_id);
4336 if (dir == DIRECTION_IN)
4337 add_trace("from", NULL, "CH(%lu)", port_id);
4338 if (param->information.id[0])
4339 add_trace("dialing", NULL, "%s", param->information.id);
4340 if (param->information.display[0])
4341 add_trace("display", NULL, "%s", param->information.display);
4342 if (param->information.sending_complete)
4343 add_trace("complete", NULL, "true", param->information.sending_complete);
4347 case MESSAGE_FACILITY:
4348 trace_header("FACILITY", dir);
4349 if (dir == DIRECTION_OUT)
4350 add_trace("to", NULL, "CH(%lu)", port_id);
4351 if (dir == DIRECTION_IN)
4352 add_trace("from", NULL, "CH(%lu)", port_id);
4357 trace_header("TONE", dir);
4358 if (dir == DIRECTION_OUT)
4359 add_trace("to", NULL, "CH(%lu)", port_id);
4360 if (dir == DIRECTION_IN)
4361 add_trace("from", NULL, "CH(%lu)", port_id);
4362 if (param->tone.name[0]) {
4363 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4364 add_trace("name", NULL, "%s", param->tone.name);
4366 add_trace("off", NULL, NULL);
4370 case MESSAGE_SUSPEND:
4371 case MESSAGE_RESUME:
4372 if (message_type == MESSAGE_SUSPEND)
4373 trace_header("SUSPEND", dir);
4375 trace_header("RESUME", dir);
4376 if (dir == DIRECTION_OUT)
4377 add_trace("to", NULL, "CH(%lu)", port_id);
4378 if (dir == DIRECTION_IN)
4379 add_trace("from", NULL, "CH(%lu)", port_id);
4380 if (param->parkinfo.len)
4381 add_trace("length", NULL, "%d", param->parkinfo.len);
4386 case MESSAGE_BCHANNEL:
4387 trace_header("BCHANNEL", dir);
4388 switch(param->bchannel.type) {
4389 case BCHANNEL_REQUEST:
4390 add_trace("type", NULL, "request");
4392 case BCHANNEL_ASSIGN:
4393 add_trace("type", NULL, "assign");
4395 case BCHANNEL_ASSIGN_ACK:
4396 add_trace("type", NULL, "assign_ack");
4398 case BCHANNEL_REMOVE:
4399 add_trace("type", NULL, "remove");
4401 case BCHANNEL_REMOVE_ACK:
4402 add_trace("type", NULL, "remove_ack");
4405 if (param->bchannel.addr)
4406 add_trace("address", NULL, "%x", param->bchannel.addr);
4412 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4416 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4418 struct lcr_msg *message;
4422 if (!portlist->port_id)
4425 if (!e_connectedmode) {
4426 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4427 message->param.disconnectinfo.cause = cause;
4428 message->param.disconnectinfo.location = location;
4430 SCPY(message->param.disconnectinfo.display, display);
4432 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4434 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4436 SCPY(message->param.notifyinfo.display, display);
4438 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4440 message_put(message);
4441 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);