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);
1011 while(*p!=',' && *p!='\0')
1013 SCCAT(ifname, *p++);
1016 /* search interface */
1017 interface = hunt_interface(ifname);
1019 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1020 add_trace("interface", NULL, "%s", ifname);
1024 /* found interface */
1025 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
1027 if (interface->gsm_bs) {
1028 SPRINT(portname, "%s-%d-out", interface->name, 0);
1029 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1030 earlyb = (interface->is_earlyb == IS_YES);
1034 if (interface->gsm_ms) {
1035 SPRINT(portname, "%s-%d-out", interface->name, 0);
1036 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1037 earlyb = (interface->is_earlyb == IS_YES);
1041 if (interface->sip) {
1042 SPRINT(portname, "%s-%d-out", interface->name, 0);
1043 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1044 earlyb = (interface->is_earlyb == IS_YES);
1048 /* hunt for mISDNport and create Port */
1049 mISDNport = hunt_port(ifname, &channel);
1051 trace_header("INTERFACE (busy)", DIRECTION_NONE);
1052 add_trace("interface", NULL, "%s", ifname);
1057 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1060 port = ss5_hunt_line(mISDNport);
1063 if (mISDNport->ifport->remote) {
1064 admin = admin_first;
1066 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1068 admin = admin->next;
1071 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1072 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1076 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1078 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);
1079 earlyb = mISDNport->earlyb;
1082 FATAL("Failed to create Port instance\n");
1083 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
1084 memset(&dialinginfo, 0, sizeof(dialinginfo));
1085 SCPY(dialinginfo.id, e_dialinginfo.id);
1086 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1087 dialinginfo.ntype = e_dialinginfo.ntype;
1088 /* create port_list relation */
1089 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1091 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1093 goto check_anycall_intern;
1095 /* directory.list */
1096 if (e_callerinfo.id[0] && e_ext.display_name) {
1097 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1099 SCPY(e_callerinfo.name, dirname);
1101 // dss1 = (class Pdss1 *)port;
1103 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1104 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1105 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1106 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1107 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1108 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1109 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1110 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1111 //terminal if (e_dialinginfo.id)
1112 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1113 /* handle restricted caller ids */
1114 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);
1115 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);
1116 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);
1117 /* display callerid if desired for extension */
1118 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));
1119 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1120 /* use cnip, if enabld */
1121 // if (!e_ext.centrex)
1122 // message->param.setup.callerinfo.name[0] = '\0';
1123 /* screen clip if prefix is required */
1124 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1125 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1126 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1127 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1129 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1130 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1131 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1132 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1134 /* use internal caller id */
1135 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1136 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1137 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1138 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1140 message_put(message);
1141 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1145 /* string from parallel call forward (cfp) */
1148 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1149 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1150 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1154 vbox_only: /* entry point for answering machine only */
1155 cfu_only: /* entry point for cfu */
1156 cfb_only: /* entry point for cfb */
1157 cfnr_only: /* entry point for cfnr */
1158 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1162 /* only if vbox should be dialed, and terminal is given */
1163 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1164 /* go to the end of p */
1167 /* answering vbox call */
1168 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1170 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1171 FATAL("No memory for VBOX Port instance\n");
1172 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1173 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1176 while(*p!=',' && *p!='\0')
1181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1182 /* hunt for mISDNport and create Port */
1183 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1185 /* creating EXTERNAL port*/
1186 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1189 port = ss5_hunt_line(mISDNport);
1192 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);
1194 FATAL("No memory for Port instance\n");
1195 earlyb = mISDNport->earlyb;
1198 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1199 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1204 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1205 goto check_anycall_intern;
1207 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1208 memset(&dialinginfo, 0, sizeof(dialinginfo));
1209 SCPY(dialinginfo.id, cfp);
1210 dialinginfo.itype = INFO_ITYPE_ISDN;
1211 dialinginfo.ntype = e_dialinginfo.ntype;
1212 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1214 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1216 goto check_anycall_intern;
1218 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1219 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1220 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1221 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1222 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1223 /* if clip is hidden */
1224 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1225 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1226 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1227 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1228 message->param.setup.callerinfo.present = e_ext.callerid_present;
1229 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1231 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1232 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1233 //terminal if (e_dialinginfo.id)
1234 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1235 /* handle restricted caller ids */
1236 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);
1237 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);
1238 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);
1239 /* display callerid if desired for extension */
1240 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));
1241 message_put(message);
1242 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1246 check_anycall_intern:
1247 /* now we have all ports created */
1249 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1251 if (!ea_endpoint->ep_join_id)
1253 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1254 return; /* must exit here */
1258 /* *********************** external call */
1260 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1261 /* call to extenal interfaces */
1262 if (e_dialinginfo.keypad[0])
1263 p = e_dialinginfo.keypad;
1265 p = e_dialinginfo.id;
1269 while(*p!=',' && *p!='\0')
1270 SCCAT(number, *p++);
1274 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");
1275 /* search interface */
1276 interface = hunt_interface(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL);
1278 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1279 add_trace("interface", NULL, "%s", ifname);
1281 goto check_anycall_extern;
1283 /* found interface */
1285 if (interface->gsm_bs) {
1286 SPRINT(portname, "%s-%d-out", interface->name, 0);
1287 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1288 earlyb = (interface->is_earlyb == IS_YES);
1292 if (interface->gsm_ms) {
1293 SPRINT(portname, "%s-%d-out", interface->name, 0);
1294 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1295 earlyb = (interface->is_earlyb == IS_YES);
1299 if (interface->sip) {
1300 SPRINT(portname, "%s-%d-out", interface->name, 0);
1301 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1302 earlyb = (interface->is_earlyb == IS_YES);
1306 /* hunt for mISDNport and create Port */
1307 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1309 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1310 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1312 goto check_anycall_extern;
1314 /* creating EXTERNAL port*/
1315 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1318 port = ss5_hunt_line(mISDNport);
1321 if (mISDNport->ifport->remote) {
1322 admin = admin_first;
1324 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1326 admin = admin->next;
1329 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1330 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1334 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1336 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);
1337 earlyb = mISDNport->earlyb;
1340 FATAL("No memory for Port instance\n");
1341 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1342 memset(&dialinginfo, 0, sizeof(dialinginfo));
1343 if (e_dialinginfo.keypad[0])
1344 SCPY(dialinginfo.keypad, number);
1346 SCPY(dialinginfo.id, number);
1347 dialinginfo.itype = INFO_ITYPE_ISDN;
1348 dialinginfo.ntype = e_dialinginfo.ntype;
1349 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1350 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1352 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1354 goto check_anycall_extern;
1356 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1357 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1358 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1359 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1360 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1361 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1362 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1363 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1364 //terminal if (e_dialinginfo.id)
1365 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1366 /* handle restricted caller ids */
1367 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);
1368 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);
1369 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);
1370 /* display callerid if desired for extension */
1371 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));
1372 message_put(message);
1373 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1377 check_anycall_extern:
1378 /* now we have all ports created */
1380 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1382 if (!ea_endpoint->ep_join_id)
1384 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1385 return; /* must exit here */
1392 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1394 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1396 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1399 unsched_timer(&ea->e_redial_timeout);
1400 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1401 ea->e_multipoint_cause = 0;
1402 ea->e_multipoint_location = 0;
1403 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1404 ea->e_join_pattern = 0;
1405 ea->process_dialing(1);
1406 /* we must exit, because our endpoint might be gone */
1411 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1413 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1415 if (!ea->e_action) {
1416 unsched_timer(&ea->e_redial_timeout);
1417 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1418 ea->process_dialing(0);
1419 /* we must exit, because our endpoint might be gone */
1425 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1427 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1429 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1431 ea->new_state(EPOINT_STATE_OUT_SETUP);
1432 /* call special setup routine */
1438 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1440 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1442 /* leave power dialing on */
1443 ea->e_powerdial_on = 1;
1444 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1447 ea->e_ruleset = ruleset_main;
1449 ea->e_rule = ea->e_ruleset->rule_first;
1450 ea->e_action = NULL;
1451 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1452 ea->process_dialing(0);
1457 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1459 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1460 struct port_list *portlist;
1461 struct lcr_msg *message;
1463 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1465 /* release all ports */
1466 while((portlist = ea->ea_endpoint->ep_portlist)) {
1467 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1468 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1469 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1470 message_put(message);
1471 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1472 ea->ea_endpoint->free_portlist(portlist);
1475 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1476 message->param.audiopath = 0;
1477 message_put(message);
1478 /* indicate no patterns */
1479 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1480 message_put(message);
1481 /* set setup state, since we have no response from the new join */
1482 ea->new_state(EPOINT_STATE_OUT_SETUP);
1487 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1489 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1491 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);
1497 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1499 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1501 if (ea->e_state == EPOINT_STATE_IDLE) {
1502 /* epoint is idle, check callback */
1503 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1504 ea->new_state(EPOINT_STATE_OUT_SETUP);
1511 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1513 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1515 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1516 struct port_list *portlist;
1518 ea->e_ruleset = ruleset_main;
1520 ea->e_rule = ea->e_ruleset->rule_first;
1521 ea->e_action = NULL;
1522 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1523 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1525 ea->e_connectedmode = 0;
1527 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1528 portlist = ea->ea_endpoint->ep_portlist;
1530 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1531 ea->set_tone(portlist, "cause_10");
1538 /* doing a hookflash */
1539 void EndpointAppPBX::hookflash(void)
1544 /* be sure that we are active */
1546 e_tx_state = NOTIFY_STATE_ACTIVE;
1548 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1550 if (ea_endpoint->ep_use > 1) {
1551 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1554 /* dialtone after pressing the hash key */
1555 process_hangup(e_join_cause, e_join_location);
1556 e_multipoint_cause = 0;
1557 e_multipoint_location = 0;
1558 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1560 port->set_echotest(0);
1562 if (ea_endpoint->ep_join_id) {
1563 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1565 e_ruleset = ruleset_main;
1567 e_rule = e_ruleset->rule_first;
1569 new_state(EPOINT_STATE_IN_OVERLAP);
1570 e_connectedmode = 1;
1571 SCPY(e_dialinginfo.id, e_ext.prefix);
1572 e_extdialing = e_dialinginfo.id;
1574 if (e_dialinginfo.id[0]) {
1575 set_tone(ea_endpoint->ep_portlist, "dialing");
1578 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1586 /* messages from port
1588 /* port MESSAGE_SETUP */
1589 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1591 struct lcr_msg *message;
1593 int writeext; /* flags need to write extension after modification */
1596 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1598 portlist->port_type = param->setup.port_type;
1599 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1600 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1601 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1602 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1603 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
1605 /* convert (inter-)national number type */
1606 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1607 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1609 // e_dtmf = param->setup.dtmf;
1610 /* screen incoming caller id */
1611 if (e_callerinfo.interface[0]) {
1612 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface);
1613 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
1616 /* process extension */
1617 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1618 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1619 /* port makes call from extension */
1620 SCPY(e_callerinfo.extension, e_callerinfo.id);
1621 SCPY(e_ext.number, e_callerinfo.extension);
1622 SCPY(e_extension_interface, e_callerinfo.interface);
1624 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1627 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1628 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1630 /* get extension's info about caller */
1631 if (!read_extension(&e_ext, e_ext.number)) {
1632 /* extension doesn't exist */
1633 trace_header("EXTENSION (not created)", DIRECTION_IN);
1634 add_trace("extension", NULL, "%s", e_ext.number);
1636 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1637 new_state(EPOINT_STATE_OUT_DISCONNECT);
1638 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1639 e_ext.number[0] = '\0'; /* no terminal */
1644 /* put prefix (next) in front of e_dialinginfo.id */
1645 if (e_ext.next[0]) {
1646 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1647 SCPY(e_dialinginfo.id, buffer);
1648 e_ext.next[0] = '\0';
1650 } else if (e_ext.prefix[0]) {
1651 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1652 SCPY(e_dialinginfo.id, buffer);
1655 /* screen caller id by extension's config */
1656 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1658 SCPY(e_callerinfo.name, e_ext.name);
1659 /* use caller id (or if exist: id_next_call) for this call */
1660 if (e_ext.id_next_call_present >= 0) {
1661 SCPY(e_callerinfo.id, e_ext.id_next_call);
1662 /* if we restrict the pesentation */
1663 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1664 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1665 else e_callerinfo.present = e_ext.id_next_call_present;
1666 e_callerinfo.ntype = e_ext.id_next_call_type;
1667 e_ext.id_next_call_present = -1;
1670 SCPY(e_callerinfo.id, e_ext.callerid);
1671 /* if we restrict the pesentation */
1672 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1673 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1674 else e_callerinfo.present = e_ext.callerid_present;
1675 e_callerinfo.ntype = e_ext.callerid_type;
1677 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1679 /* extension is written */
1681 write_extension(&e_ext, e_ext.number);
1683 /* set volume of rx and tx */
1684 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1685 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1686 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1687 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1688 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1689 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1690 message_put(message);
1693 /* start recording if enabled */
1694 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1695 /* check if we are a terminal */
1696 if (e_ext.number[0] == '\0')
1697 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1699 port = find_port_id(portlist->port_id);
1701 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1705 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1706 /* no terminal identification */
1707 e_ext.number[0] = '\0';
1708 e_extension_interface[0] = '\0';
1709 memset(&e_ext, 0, sizeof(e_ext));
1710 e_ext.rights = 4; /* right to dial internat */
1714 e_ruleset = ruleset_main;
1716 e_rule = e_ruleset->rule_first;
1718 e_extdialing = e_dialinginfo.id;
1719 new_state(EPOINT_STATE_IN_SETUP);
1720 if (e_dialinginfo.id[0]) {
1721 set_tone(portlist, "dialing");
1723 if (e_ext.number[0])
1724 set_tone(portlist, "dialpbx");
1726 set_tone(portlist, "dialtone");
1729 if (e_state == EPOINT_STATE_IN_SETUP) {
1730 /* request MORE info, if not already at higher state */
1731 new_state(EPOINT_STATE_IN_OVERLAP);
1732 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1733 message_put(message);
1734 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1738 /* port MESSAGE_INFORMATION */
1739 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1741 struct lcr_msg *message;
1743 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1745 /* ignore information message without digit information */
1746 if (!param->information.id[0])
1751 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1753 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1758 /* if vbox_play is done, the information are just used as they come */
1760 if (e_action->index == ACTION_VBOX_PLAY) {
1761 /* concat dialing string */
1762 SCAT(e_dialinginfo.id, param->information.id);
1767 /* keypad when disconnect but in connected mode */
1768 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1769 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1770 /* processing keypad function */
1771 if (param->information.id[0] == '0') {
1777 /* keypad when connected */
1778 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1779 if (e_enablekeypad) {
1780 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1781 memcpy(&message->param, param, sizeof(union parameter));
1782 message_put(message);
1786 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1787 /* processing keypad function */
1788 if (param->information.id[0] == '0') {
1791 if (param->information.id[0])
1792 keypad_function(param->information.id[0]);
1794 if (e_ext.number[0])
1795 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1797 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1802 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1803 if (e_ext.number[0])
1804 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1806 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1810 if (!param->information.id[0])
1812 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1813 set_tone(portlist, "dialing");
1816 if (e_action->index==ACTION_OUTDIAL
1817 || e_action->index==ACTION_EXTERNAL
1818 || e_action->index==ACTION_REMOTE) {
1820 set_tone(portlist, "dialing");
1821 else if (!e_extdialing[0])
1822 set_tone(portlist, "dialing");
1824 /* concat dialing string */
1825 SCAT(e_dialinginfo.id, param->information.id);
1829 /* port MESSAGE_DTMF */
1830 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1833 struct lcr_msg *message;
1837 /* only if dtmf detection is enabled */
1839 trace_header("DTMF (disabled)", DIRECTION_IN);
1843 trace_header("DTMF", DIRECTION_IN);
1844 add_trace("digit", NULL, "%c", param->dtmf);
1848 NOTE: vbox is now handled due to overlap state
1849 /* if vbox_play is done, the dtmf digits are just used as they come */
1851 if (e_action->index == ACTION_VBOX_PLAY) {
1852 /* concat dialing string */
1853 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1854 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1855 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1858 /* continue to process *X# sequences */
1862 /* check for *X# sequence */
1863 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1864 if (e_enablekeypad) {
1865 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1866 memcpy(&message->param, param, sizeof(union parameter));
1867 message_put(message);
1870 if (e_dtmf_time+3 < now) {
1871 /* the last digit was too far in the past to be a sequence */
1872 if (param->dtmf == '*')
1873 /* only start is allowed in the sequence */
1878 /* we have a sequence of digits, see what we got */
1879 if (param->dtmf == '*')
1881 else if (param->dtmf>='0' && param->dtmf<='9') {
1882 /* we need to have a star before we receive the digit of the sequence */
1883 if (e_dtmf_last == '*')
1884 e_dtmf_last = param->dtmf;
1885 } else if (param->dtmf == '#') {
1887 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1888 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1889 if (e_dtmf_last == '0') {
1893 /* processing keypad function */
1895 keypad_function(e_dtmf_last);
1901 /* set last time of dtmf */
1906 /* check for ## hookflash during dialing */
1908 if (e_action->index==ACTION_PASSWORD
1909 || e_action->index==ACTION_PASSWORD_WRITE)
1911 if (param->dtmf=='#') { /* current digit is '#' */
1912 if (e_state==EPOINT_STATE_IN_DISCONNECT
1913 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1927 /* dialing using dtmf digit */
1928 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1929 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1930 set_tone(portlist, "dialing");
1932 /* concat dialing string */
1933 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1934 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1935 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1941 /* port MESSAGE_CRYPT */
1942 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1944 /* send crypt response to cryptman */
1945 if (param->crypt.type == CR_MESSAGE_IND)
1946 cryptman_msg2man(param->crypt.data, param->crypt.len);
1948 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1951 /* port MESSAGE_OVERLAP */
1952 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1954 struct lcr_msg *message;
1956 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1958 /* signal to call tool */
1959 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1961 if (e_dialing_queue[0] && portlist) {
1962 /* send what we have not dialed yet, because we had no setup complete */
1963 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1964 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1965 SCPY(message->param.information.id, e_dialing_queue);
1966 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1967 message_put(message);
1968 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1969 e_dialing_queue[0] = '\0';
1971 /* check if pattern is available */
1972 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
1973 /* indicate patterns */
1974 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1975 message_put(message);
1977 /* connect 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 = 1;
1980 message_put(message);
1982 /* indicate no patterns */
1983 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1984 message_put(message);
1986 /* disconnect audio, if not already */
1987 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1988 message->param.audiopath = 0;
1989 message_put(message);
1991 new_state(EPOINT_STATE_OUT_OVERLAP);
1992 /* if we are in a join */
1993 if (ea_endpoint->ep_join_id) {
1994 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1995 memcpy(&message->param, param, sizeof(union parameter));
1996 message_put(message);
2000 /* port MESSAGE_PROCEEDING */
2001 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2003 struct lcr_msg *message;
2005 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2007 /* signal to call tool */
2008 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
2010 e_state = EPOINT_STATE_OUT_PROCEEDING;
2011 /* check if pattern is availatle */
2012 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
2013 /* indicate patterns */
2014 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2015 message_put(message);
2017 /* connect 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 = 1;
2020 message_put(message);
2022 /* indicate no patterns */
2023 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
2024 message_put(message);
2026 /* disconnect audio, if not already */
2027 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2028 message->param.audiopath = 0;
2029 message_put(message);
2031 /* if we are in a call */
2032 if (ea_endpoint->ep_join_id) {
2033 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2034 memcpy(&message->param, param, sizeof(union parameter));
2035 message_put(message);
2039 /* port MESSAGE_ALERTING */
2040 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
2042 struct lcr_msg *message;
2044 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2046 /* signal to call tool */
2047 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
2050 // set_tone(portlist, "hold");
2052 new_state(EPOINT_STATE_OUT_ALERTING);
2053 /* check if pattern is available */
2054 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
2055 /* indicate patterns */
2056 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2057 message_put(message);
2059 /* connect 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 = 1;
2062 message_put(message);
2064 /* indicate no patterns */
2065 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
2066 message_put(message);
2068 /* disconnect audio, if not already */
2069 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2070 message->param.audiopath = 0;
2071 message_put(message);
2073 /* if we are in a call */
2074 if (ea_endpoint->ep_join_id) {
2075 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2076 memcpy(&message->param, param, sizeof(union parameter));
2077 message_put(message);
2081 /* port MESSAGE_CONNECT */
2082 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
2084 struct lcr_msg *message;
2086 unsigned int port_id = portlist->port_id;
2087 struct port_list *tportlist;
2091 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2093 /* signal to call tool */
2094 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
2096 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
2097 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2098 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
2099 tportlist = ea_endpoint->ep_portlist;
2100 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2101 tportlist = tportlist->next;
2102 if (tportlist->port_id == port_id)
2103 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2104 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2105 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
2106 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2107 message_put(message);
2108 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
2109 ea_endpoint->free_portlist(tportlist);
2111 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2116 if (e_callerinfo.interface[0])
2117 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface);
2119 /* screen connected name */
2121 SCPY(e_connectinfo.name, e_ext.name);
2123 /* add internal id to colp */
2124 SCPY(e_connectinfo.extension, e_ext.number);
2126 /* we store the connected port number */
2127 SCPY(e_extension_interface, e_connectinfo.interface);
2129 /* for internal and am calls, we get the extension's id */
2130 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
2131 SCPY(e_connectinfo.id, e_ext.callerid);
2132 SCPY(e_connectinfo.extension, e_ext.number);
2133 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2134 e_connectinfo.ntype = e_ext.callerid_type;
2135 e_connectinfo.present = e_ext.callerid_present;
2137 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2138 e_connectinfo.itype = INFO_ITYPE_VBOX;
2139 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2142 new_state(EPOINT_STATE_CONNECT);
2144 /* set volume of rx and tx */
2145 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2146 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2147 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2148 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2149 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2150 message_put(message);
2153 unsched_timer(&e_cfnr_timeout);
2154 unsched_timer(&e_cfnr_call_timeout);
2155 if (e_ext.number[0])
2156 e_dtmf = 1; /* allow dtmf */
2159 /* other calls with no caller id (or not available for the extension) and force colp */
2160 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2161 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2162 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
2163 /* external extension answered */
2164 port = find_port_id(portlist->port_id);
2166 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2167 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2172 /* send connect to join */
2173 if (ea_endpoint->ep_join_id) {
2174 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2175 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2176 message_put(message);
2178 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2179 message->param.audiopath = 1;
2180 message_put(message);
2181 } else if (!e_adminid) {
2183 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2184 SCPY(e_ext.number, e_cbcaller);
2185 new_state(EPOINT_STATE_IN_OVERLAP);
2186 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2188 /* get extension's info about terminal */
2189 if (!read_extension(&e_ext, e_ext.number)) {
2190 /* extension doesn't exist */
2191 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2192 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2193 new_state(EPOINT_STATE_OUT_DISCONNECT);
2194 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2198 /* put prefix in front of e_cbdialing */
2199 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2200 SCPY(e_dialinginfo.id, buffer);
2201 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2202 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2204 /* use caller id (or if exist: id_next_call) for this call */
2205 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2206 SCPY(e_callerinfo.extension, e_ext.number);
2207 if (e_ext.id_next_call_present >= 0) {
2208 SCPY(e_callerinfo.id, e_ext.id_next_call);
2209 e_callerinfo.present = e_ext.id_next_call_present;
2210 e_callerinfo.ntype = e_ext.id_next_call_type;
2211 e_ext.id_next_call_present = -1;
2212 /* extension is written */
2213 write_extension(&e_ext, e_ext.number);
2215 SCPY(e_callerinfo.id, e_ext.callerid);
2216 e_callerinfo.present = e_ext.callerid_present;
2217 e_callerinfo.ntype = e_ext.callerid_type;
2219 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2221 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2224 /* check if caller id is NOT authenticated */
2225 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2226 /* make call state to enter password */
2227 new_state(EPOINT_STATE_IN_OVERLAP);
2228 e_action = &action_password_write;
2229 unsched_timer(&e_match_timeout);
2230 e_match_to_action = NULL;
2231 e_dialinginfo.id[0] = '\0';
2232 e_extdialing = strchr(e_dialinginfo.id, '\0');
2233 schedule_timer(&e_password_timeout, 20, 0);
2236 /* incoming call (callback) */
2237 e_ruleset = ruleset_main;
2239 e_rule = e_ruleset->rule_first;
2241 e_extdialing = e_dialinginfo.id;
2242 if (e_dialinginfo.id[0]) {
2243 set_tone(portlist, "dialing");
2246 set_tone(portlist, "dialpbx");
2249 } else { /* testcall */
2250 set_tone(portlist, "hold");
2253 /* start recording if enabled, not when answering machine answers */
2254 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)) {
2255 /* check if we are a terminal */
2256 if (e_ext.number[0] == '\0')
2257 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2259 port = find_port_id(portlist->port_id);
2261 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2266 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2267 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2269 struct lcr_msg *message;
2271 unsigned int port_id = portlist->port_id;
2275 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2277 /* signal to call tool */
2278 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2280 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2281 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2282 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2287 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);
2288 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2289 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2291 /* check if we have more than one portlist relation and we just ignore the disconnect */
2292 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2293 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2294 portlist = ea_endpoint->ep_portlist;
2296 if (portlist->port_id == port_id)
2298 portlist = portlist->next;
2301 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2302 if (message_type != MESSAGE_RELEASE) {
2303 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2304 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2305 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2306 message_put(message);
2307 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2309 ea_endpoint->free_portlist(portlist);
2310 return; /* one relation removed */
2312 if (e_state == EPOINT_STATE_CONNECT) {
2313 /* use cause from port after connect */
2314 cause = param->disconnectinfo.cause;
2315 location = param->disconnectinfo.location;
2317 /* use multipoint cause if no connect yet */
2318 if (e_multipoint_cause) {
2319 cause = e_multipoint_cause;
2320 location = e_multipoint_location;
2322 cause = CAUSE_NOUSER;
2323 location = LOCATION_PRIVATE_LOCAL;
2327 unsched_timer(&e_cfnr_timeout);
2328 unsched_timer(&e_cfnr_call_timeout);
2330 /* process hangup */
2331 process_hangup(e_join_cause, e_join_location);
2332 e_multipoint_cause = 0;
2333 e_multipoint_location = 0;
2335 if (message_type == MESSAGE_DISCONNECT) {
2336 /* tone to disconnected end */
2337 SPRINT(buffer, "cause_%02x", cause);
2338 if (ea_endpoint->ep_portlist)
2339 set_tone(ea_endpoint->ep_portlist, buffer);
2341 new_state(EPOINT_STATE_IN_DISCONNECT);
2344 if (ea_endpoint->ep_join_id) {
2345 int haspatterns = 0;
2346 /* check if pattern is available */
2347 if (ea_endpoint->ep_portlist)
2348 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2349 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
2350 && message_type != MESSAGE_RELEASE) // if we release, we are done
2353 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2354 /* indicate patterns */
2355 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2356 message_put(message);
2357 /* connect audio, if not already */
2358 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2359 message->param.audiopath = 1;
2360 message_put(message);
2361 /* send disconnect */
2362 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2363 memcpy(&message->param, param, sizeof(union parameter));
2364 message_put(message);
2365 /* disable encryption if disconnected */
2366 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2368 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2371 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2374 if (message_type == MESSAGE_RELEASE)
2375 ea_endpoint->free_portlist(portlist);
2376 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2377 return; /* must exit here */
2380 /* port MESSAGE_TIMEOUT */
2381 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2385 trace_header("TIMEOUT", DIRECTION_IN);
2386 message_type = MESSAGE_DISCONNECT;
2387 switch (param->state) {
2388 case PORT_STATE_OUT_SETUP:
2389 case PORT_STATE_OUT_OVERLAP:
2390 add_trace("state", NULL, "outgoing setup/dialing");
2392 /* no user responding */
2393 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2394 return; /* must exit here */
2396 case PORT_STATE_IN_SETUP:
2397 case PORT_STATE_IN_OVERLAP:
2398 add_trace("state", NULL, "incoming setup/dialing");
2399 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2400 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2403 case PORT_STATE_OUT_PROCEEDING:
2404 add_trace("state", NULL, "outgoing proceeding");
2406 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2407 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2408 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2409 return; /* must exit here */
2411 case PORT_STATE_IN_PROCEEDING:
2412 add_trace("state", NULL, "incoming proceeding");
2413 param->disconnectinfo.cause = CAUSE_NOUSER;
2414 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2417 case PORT_STATE_OUT_ALERTING:
2418 add_trace("state", NULL, "outgoing alerting");
2420 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2421 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2422 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2423 return; /* must exit here */
2425 case PORT_STATE_CONNECT:
2426 add_trace("state", NULL, "connect");
2428 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2429 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2430 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2431 return; /* must exit here */
2433 case PORT_STATE_IN_ALERTING:
2434 add_trace("state", NULL, "incoming alerting");
2435 param->disconnectinfo.cause = CAUSE_NOANSWER;
2436 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2439 case PORT_STATE_IN_DISCONNECT:
2440 case PORT_STATE_OUT_DISCONNECT:
2441 add_trace("state", NULL, "disconnect");
2443 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2444 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2445 return; /* must exit here */
2448 param->disconnectinfo.cause = 31; /* normal unspecified */
2449 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2452 /* release call, disconnect isdn */
2454 new_state(EPOINT_STATE_OUT_DISCONNECT);
2455 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2456 SCPY(e_tone, cause);
2458 set_tone(portlist, cause);
2459 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2460 portlist = portlist->next;
2462 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2465 /* port MESSAGE_NOTIFY */
2466 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2468 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2470 struct lcr_msg *message;
2471 const char *logtext = "";
2474 /* signal to call tool */
2475 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);
2476 if (param->notifyinfo.notify) {
2477 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2480 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2481 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2482 case INFO_NOTIFY_REMOTE_HOLD:
2483 case INFO_NOTIFY_USER_SUSPENDED:
2484 /* tell call about it */
2485 if (ea_endpoint->ep_join_id) {
2486 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2487 message->param.audiopath = 0;
2488 message_put(message);
2492 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2493 case INFO_NOTIFY_USER_RESUMED:
2494 /* set volume of rx and tx */
2495 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2496 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2498 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2499 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2500 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2501 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2502 message_put(message);
2504 /* set current tone */
2506 set_tone(portlist, e_tone);
2507 /* tell call about it */
2508 if (ea_endpoint->ep_join_id) {
2509 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2510 message->param.audiopath = 1;
2511 message_put(message);
2516 /* get name of notify */
2517 switch(param->notifyinfo.notify) {
2522 logtext = "USER_SUSPENDED";
2525 logtext = "BEARER_SERVICE_CHANGED";
2528 logtext = "USER_RESUMED";
2531 logtext = "CONFERENCE_ESTABLISHED";
2534 logtext = "CONFERENCE_DISCONNECTED";
2537 logtext = "OTHER_PARTY_ADDED";
2540 logtext = "ISOLATED";
2543 logtext = "REATTACHED";
2546 logtext = "OTHER_PARTY_ISOLATED";
2549 logtext = "OTHER_PARTY_REATTACHED";
2552 logtext = "OTHER_PARTY_SPLIT";
2555 logtext = "OTHER_PARTY_DISCONNECTED";
2558 logtext = "CONFERENCE_FLOATING";
2561 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2564 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2567 logtext = "CALL_IS_A_WAITING_CALL";
2570 logtext = "DIVERSION_ACTIVATED";
2573 logtext = "RESERVED_CT_1";
2576 logtext = "RESERVED_CT_2";
2579 logtext = "REVERSE_CHARGING";
2582 logtext = "REMOTE_HOLD";
2585 logtext = "REMOTE_RETRIEVAL";
2588 logtext = "CALL_IS_DIVERTING";
2591 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2596 /* notify call if available */
2597 if (ea_endpoint->ep_join_id) {
2598 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2599 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2600 message_put(message);
2605 /* port MESSAGE_PROGRESS */
2606 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2608 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2610 struct lcr_msg *message;
2612 /* signal to call tool */
2613 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2615 /* send progress to call if available */
2616 if (ea_endpoint->ep_join_id) {
2617 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2618 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2619 message_put(message);
2624 /* port MESSAGE_FACILITY */
2625 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2627 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2629 struct lcr_msg *message;
2631 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2632 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2633 message_put(message);
2636 /* port MESSAGE_SUSPEND */
2637 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2638 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2640 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2642 /* epoint is now parked */
2643 ea_endpoint->ep_park = 1;
2644 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2645 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2647 /* remove port relation */
2648 ea_endpoint->free_portlist(portlist);
2651 /* port MESSAGE_RESUME */
2652 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2653 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2655 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2657 /* epoint is now resumed */
2658 ea_endpoint->ep_park = 0;
2662 /* port MESSAGE_ENABLEKEYPAD */
2663 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2665 struct lcr_msg *message;
2667 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2669 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2670 memcpy(&message->param, param, sizeof(union parameter));
2671 message_put(message);
2675 /* port sends message to the endpoint
2677 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2679 struct port_list *portlist;
2681 portlist = ea_endpoint->ep_portlist;
2683 if (port_id == portlist->port_id)
2685 portlist = portlist->next;
2688 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);
2692 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2693 switch(message_type) {
2694 case MESSAGE_TONE_EOF: /* tone is end of file */
2695 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2697 if (e_action->index == ACTION_VBOX_PLAY) {
2700 if (e_action->index == ACTION_EFI) {
2706 case MESSAGE_TONE_COUNTER: /* counter info received */
2707 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);
2709 if (e_action->index == ACTION_VBOX_PLAY) {
2710 e_vbox_counter = param->counter.current;
2711 if (param->counter.max >= 0)
2712 e_vbox_counter_max = param->counter.max;
2716 /* PORT sends SETUP message */
2718 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);
2719 if (e_state!=EPOINT_STATE_IDLE) {
2720 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2723 port_setup(portlist, message_type, param);
2726 /* PORT sends INFORMATION message */
2727 case MESSAGE_INFORMATION: /* additional digits received */
2728 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);
2729 port_information(portlist, message_type, param);
2732 /* PORT sends FACILITY message */
2733 case MESSAGE_FACILITY:
2734 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2735 port_facility(portlist, message_type, param);
2738 /* PORT sends DTMF message */
2739 case MESSAGE_DTMF: /* dtmf digits received */
2740 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);
2741 port_dtmf(portlist, message_type, param);
2744 /* PORT sends CRYPT message */
2745 case MESSAGE_CRYPT: /* crypt response received */
2746 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2747 port_crypt(portlist, message_type, param);
2750 /* PORT sends MORE message */
2751 case MESSAGE_OVERLAP:
2752 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);
2753 if (e_state != EPOINT_STATE_OUT_SETUP) {
2754 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);
2757 port_overlap(portlist, message_type, param);
2760 /* PORT sends PROCEEDING message */
2761 case MESSAGE_PROCEEDING: /* port is proceeding */
2762 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);
2763 if (e_state!=EPOINT_STATE_OUT_SETUP
2764 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2765 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);
2768 port_proceeding(portlist, message_type, param);
2771 /* PORT sends ALERTING message */
2772 case MESSAGE_ALERTING:
2773 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);
2774 if (e_state!=EPOINT_STATE_OUT_SETUP
2775 && e_state!=EPOINT_STATE_OUT_OVERLAP
2776 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2777 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);
2780 port_alerting(portlist, message_type, param);
2783 /* PORT sends CONNECT message */
2784 case MESSAGE_CONNECT:
2785 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);
2786 if (e_state!=EPOINT_STATE_OUT_SETUP
2787 && e_state!=EPOINT_STATE_OUT_OVERLAP
2788 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2789 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2790 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2793 port_connect(portlist, message_type, param);
2796 /* PORT sends DISCONNECT message */
2797 case MESSAGE_DISCONNECT: /* port is disconnected */
2798 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);
2799 port_disconnect_release(portlist, message_type, param);
2802 /* PORT sends a RELEASE message */
2803 case MESSAGE_RELEASE: /* port releases */
2804 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);
2805 /* portlist is release at port_disconnect_release, thanx Paul */
2806 port_disconnect_release(portlist, message_type, param);
2809 /* PORT sends a TIMEOUT message */
2810 case MESSAGE_TIMEOUT:
2811 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);
2812 port_timeout(portlist, message_type, param);
2813 break; /* release */
2815 /* PORT sends a NOTIFY message */
2816 case MESSAGE_NOTIFY:
2817 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);
2818 port_notify(portlist, message_type, param);
2821 /* PORT sends a PROGRESS message */
2822 case MESSAGE_PROGRESS:
2823 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);
2824 port_progress(portlist, message_type, param);
2827 /* PORT sends a SUSPEND message */
2828 case MESSAGE_SUSPEND:
2829 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);
2830 port_suspend(portlist, message_type, param);
2831 break; /* suspend */
2833 /* PORT sends a RESUME message */
2834 case MESSAGE_RESUME:
2835 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);
2836 port_resume(portlist, message_type, param);
2840 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2841 /* port assigns bchannel */
2842 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2843 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);
2844 /* only one port is expected to be connected to bchannel */
2845 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2846 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2850 /* PORT requests DTMF */
2851 case MESSAGE_ENABLEKEYPAD:
2852 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);
2853 port_enablekeypad(portlist, message_type, param);
2858 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);
2861 /* Note: this endpoint may be destroyed, so we MUST return */
2865 /* messages from join
2867 /* join MESSAGE_CRYPT */
2868 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2870 switch(param->crypt.type) {
2871 /* message from remote port to "crypt manager" */
2872 case CU_ACTK_REQ: /* activate key-exchange */
2873 case CU_ACTS_REQ: /* activate shared key */
2874 case CU_DACT_REQ: /* deactivate */
2875 case CU_INFO_REQ: /* request last info message */
2876 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2879 /* message from "crypt manager" to user */
2880 case CU_ACTK_CONF: /* key-echange done */
2881 case CU_ACTS_CONF: /* shared key done */
2882 case CU_DACT_CONF: /* deactivated */
2883 case CU_DACT_IND: /* deactivated */
2884 case CU_ERROR_IND: /* receive error message */
2885 case CU_INFO_IND: /* receive info message */
2886 case CU_INFO_CONF: /* receive info message */
2887 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2891 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);
2895 /* join MESSAGE_INFORMATION */
2896 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2898 struct lcr_msg *message;
2903 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2904 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2905 message_put(message);
2906 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2907 portlist = portlist->next;
2911 /* join MESSAGE_FACILITY */
2912 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2914 struct lcr_msg *message;
2916 if (!e_ext.facility && e_ext.number[0]) {
2921 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2922 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2923 message_put(message);
2924 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2925 portlist = portlist->next;
2929 /* join MESSAGE_MORE */
2930 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2932 struct lcr_msg *message;
2934 new_state(EPOINT_STATE_IN_OVERLAP);
2937 if (e_join_pattern && e_ext.own_setup) {
2938 /* disconnect audio */
2939 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2940 message->param.audiopath = 0;
2941 message_put(message);
2943 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2944 if (e_dialinginfo.id[0])
2945 set_tone(portlist, "dialing");
2947 set_tone(portlist, "dialtone");
2950 if (e_dialinginfo.id[0]) {
2951 set_tone(portlist, "dialing");
2953 if (e_ext.number[0])
2954 set_tone(portlist, "dialpbx");
2956 set_tone(portlist, "dialtone");
2960 /* join MESSAGE_PROCEEDING */
2961 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2963 struct lcr_msg *message;
2965 new_state(EPOINT_STATE_IN_PROCEEDING);
2967 /* own proceeding tone */
2968 if (e_join_pattern) {
2969 /* connect / disconnect audio */
2970 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2971 if (e_ext.own_proceeding)
2972 message->param.audiopath = 0;
2974 message->param.audiopath = 1;
2975 message_put(message);
2977 // UCPY(e_join_tone, "proceeding");
2979 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2980 message_put(message);
2981 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2983 set_tone(portlist, "proceeding");
2986 /* join MESSAGE_ALERTING */
2987 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2989 struct lcr_msg *message;
2991 new_state(EPOINT_STATE_IN_ALERTING);
2993 /* own alerting tone */
2994 if (e_join_pattern) {
2995 /* connect / disconnect audio */
2996 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2997 if (e_ext.own_alerting)
2998 message->param.audiopath = 0;
3000 message->param.audiopath = 1;
3001 message_put(message);
3004 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
3005 message_put(message);
3006 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3008 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
3009 set_tone(portlist, "ringing");
3012 if (e_ext.number[0])
3013 set_tone(portlist, "ringpbx");
3015 set_tone(portlist, "ringing");
3017 if (e_ext.number[0])
3018 e_dtmf = 1; /* allow dtmf */
3021 /* join MESSAGE_CONNECT */
3022 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
3024 struct lcr_msg *message;
3027 new_state(EPOINT_STATE_CONNECT);
3028 // UCPY(e_join_tone, "");
3030 if (e_ext.number[0])
3031 e_dtmf = 1; /* allow dtmf */
3034 unsched_timer(&e_powerdial_timeout);
3035 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
3037 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3038 memcpy(&message->param, param, sizeof(union parameter));
3040 /* screen clip if prefix is required */
3041 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
3042 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
3043 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
3044 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3047 /* use internal caller id */
3048 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
3049 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
3050 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3053 /* handle restricted caller ids */
3054 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);
3055 /* display callerid if desired for extension */
3056 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));
3058 /* use conp, if enabld */
3059 // if (!e_ext.centrex)
3060 // message->param.connectinfo.name[0] = '\0';
3063 message_put(message);
3064 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3066 set_tone(portlist, NULL);
3068 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3069 message->param.audiopath = 1;
3070 message_put(message);
3075 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3076 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3079 struct lcr_msg *message;
3080 struct port_list *portlist = NULL;
3084 /* be sure that we are active */
3086 e_tx_state = NOTIFY_STATE_ACTIVE;
3088 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
3089 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
3090 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
3092 /* set time for power dialing */
3093 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
3096 /* set redial tone */
3097 if (ea_endpoint->ep_portlist) {
3100 set_tone(ea_endpoint->ep_portlist, "redial");
3101 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);
3102 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3103 if (e_state==EPOINT_STATE_IN_OVERLAP) {
3104 new_state(EPOINT_STATE_IN_PROCEEDING);
3105 if (ea_endpoint->ep_portlist) {
3106 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3107 message_put(message);
3108 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3110 /* caused the error, that the first knock sound was not there */
3111 /* set_tone(portlist, "proceeding"); */
3113 /* send display of powerdialing */
3114 if (e_ext.display_dialing) {
3115 portlist = ea_endpoint->ep_portlist;
3117 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3119 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3121 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3122 message_put(message);
3123 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3124 portlist = portlist->next;
3134 if ((e_state!=EPOINT_STATE_CONNECT
3135 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3136 && e_state!=EPOINT_STATE_IN_OVERLAP
3137 && e_state!=EPOINT_STATE_IN_PROCEEDING
3138 && e_state!=EPOINT_STATE_IN_ALERTING)
3139 || !ea_endpoint->ep_portlist) { /* or no port */
3140 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3141 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3142 return; /* must exit here */
3145 if (!e_join_cause) {
3146 e_join_cause = param->disconnectinfo.cause;
3147 e_join_location = param->disconnectinfo.location;
3150 /* on release we need the audio again! */
3151 if (message_type == MESSAGE_RELEASE) {
3153 ea_endpoint->ep_join_id = 0;
3155 /* disconnect and select tone */
3156 new_state(EPOINT_STATE_OUT_DISCONNECT);
3157 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3158 /* if own_cause, we must release the join */
3159 if (e_ext.own_cause /* own cause */
3160 || !e_join_pattern) { /* no patterns */
3161 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);
3162 if (message_type != MESSAGE_RELEASE)
3163 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3165 } else { /* else we enable audio */
3166 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3167 message->param.audiopath = 1;
3168 message_put(message);
3170 /* send disconnect message */
3171 SCPY(e_tone, cause);
3172 portlist = ea_endpoint->ep_portlist;
3174 set_tone(portlist, cause);
3175 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3176 portlist = portlist->next;
3180 /* join MESSAGE_SETUP */
3181 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3183 struct lcr_msg *message;
3184 // struct interface *interface;
3186 /* if we already in setup state, we just update the dialing with new digits */
3187 if (e_state == EPOINT_STATE_OUT_SETUP
3188 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3189 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3190 /* if digits changed, what we have already dialed */
3191 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3192 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);
3193 /* release all ports */
3194 while((portlist = ea_endpoint->ep_portlist)) {
3195 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3196 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3197 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3198 message_put(message);
3199 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3200 ea_endpoint->free_portlist(portlist);
3203 /* disconnect audio */
3204 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3205 message->param.audiopath = 0;
3206 message_put(message);
3208 /* get dialing info */
3209 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3210 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3211 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3212 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3213 new_state(EPOINT_STATE_OUT_OVERLAP);
3216 schedule_timer(&e_redial_timeout, 1, 0);
3219 /* if we have a pending redial, so we just adjust the dialing number */
3220 if (e_redial_timeout.active) {
3221 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);
3222 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3225 if (!ea_endpoint->ep_portlist) {
3226 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3228 if (ea_endpoint->ep_portlist->next) {
3229 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3231 if (e_state == EPOINT_STATE_OUT_SETUP) {
3233 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);
3234 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3237 /* get what we have not dialed yet */
3238 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));
3239 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3240 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3241 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3242 message_put(message);
3243 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3245 /* always store what we have dialed or queued */
3246 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3250 if (e_state != EPOINT_STATE_IDLE) {
3251 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3254 /* if an internal extension is dialed, copy that number */
3255 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3256 SCPY(e_ext.number, param->setup.dialinginfo.id);
3257 /* if an internal extension is dialed, get extension's info about caller */
3258 if (e_ext.number[0]) {
3259 if (!read_extension(&e_ext, e_ext.number)) {
3260 e_ext.number[0] = '\0';
3261 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3265 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3266 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3267 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3268 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3269 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3271 /* process (voice over) data calls */
3272 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3273 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3274 memset(&e_capainfo, 0, sizeof(e_capainfo));
3275 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3276 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3277 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3280 new_state(EPOINT_STATE_OUT_SETUP);
3281 /* call special setup routine */
3285 /* join MESSAGE_mISDNSIGNAL */
3286 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3288 struct lcr_msg *message;
3291 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3292 memcpy(&message->param, param, sizeof(union parameter));
3293 message_put(message);
3294 portlist = portlist->next;
3298 /* join MESSAGE_BRIDE */
3299 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3301 struct lcr_msg *message;
3304 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3305 memcpy(&message->param, param, sizeof(union parameter));
3306 message_put(message);
3307 portlist = portlist->next;
3311 /* join MESSAGE_NOTIFY */
3312 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3314 struct lcr_msg *message;
3317 if (param->notifyinfo.notify) {
3318 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3319 // /* if notification was generated locally, we turn hold music on/off */
3320 // if (param->notifyinfo.local)
3321 // 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)
3325 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3326 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3328 set_tone(portlist, "");
3329 portlist = portlist->next;
3332 portlist = ea_endpoint->ep_portlist;
3337 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3339 set_tone(portlist, "hold");
3340 portlist = portlist->next;
3342 portlist = ea_endpoint->ep_portlist;
3347 /* save new state */
3348 e_tx_state = new_state;
3351 /* notify port(s) about it */
3353 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3354 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3355 /* handle restricted caller ids */
3356 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3357 /* display callerid if desired for extension */
3358 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));
3359 message_put(message);
3360 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3361 portlist = portlist->next;
3365 /* join MESSAGE_DTMF */
3366 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3368 struct lcr_msg *message;
3371 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3372 memcpy(&message->param, param, sizeof(union parameter));
3373 message_put(message);
3374 portlist = portlist->next;
3378 /* JOIN sends messages to the endpoint
3380 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3382 struct port_list *portlist;
3383 struct lcr_msg *message;
3386 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3390 portlist = ea_endpoint->ep_portlist;
3392 // 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);
3393 switch(message_type) {
3394 /* JOIN SENDS TONE message */
3396 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);
3397 set_tone(portlist, param->tone.name);
3400 /* JOIN SENDS CRYPT message */
3402 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);
3403 join_crypt(portlist, message_type, param);
3406 /* JOIN sends INFORMATION message */
3407 case MESSAGE_INFORMATION:
3408 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);
3409 join_information(portlist, message_type, param);
3412 /* JOIN sends FACILITY message */
3413 case MESSAGE_FACILITY:
3414 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);
3415 join_facility(portlist, message_type, param);
3418 /* JOIN sends OVERLAP message */
3419 case MESSAGE_OVERLAP:
3420 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);
3421 if (e_state!=EPOINT_STATE_IN_SETUP
3422 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3423 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3426 join_overlap(portlist, message_type, param);
3429 /* JOIN sends PROCEEDING message */
3430 case MESSAGE_PROCEEDING:
3431 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);
3432 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3433 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3436 join_proceeding(portlist, message_type, param);
3439 /* JOIN sends ALERTING message */
3440 case MESSAGE_ALERTING:
3441 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);
3442 if (e_state!=EPOINT_STATE_IN_OVERLAP
3443 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3444 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3447 join_alerting(portlist, message_type, param);
3450 /* JOIN sends CONNECT message */
3451 case MESSAGE_CONNECT:
3452 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);
3453 if (e_state!=EPOINT_STATE_IN_OVERLAP
3454 && e_state!=EPOINT_STATE_IN_PROCEEDING
3455 && e_state!=EPOINT_STATE_IN_ALERTING) {
3456 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3459 join_connect(portlist, message_type, param);
3462 /* JOIN sends DISCONNECT/RELEASE message */
3463 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3464 case MESSAGE_RELEASE: /* JOIN releases */
3465 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);
3466 join_disconnect_release(message_type, param);
3469 /* JOIN sends SETUP message */
3471 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);
3472 join_setup(portlist, message_type, param);
3475 /* JOIN sends special mISDNSIGNAL message */
3476 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3477 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);
3478 join_mISDNsignal(portlist, message_type, param);
3481 /* JOIN sends bridge message */
3482 case MESSAGE_BRIDGE: /* bride message to port */
3483 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);
3484 join_bridge(portlist, message_type, param);
3487 /* JOIN has pattern available */
3488 case MESSAGE_PATTERN: /* indicating pattern available */
3489 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);
3490 if (!e_join_pattern) {
3491 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3495 set_tone(portlist, NULL);
3496 portlist = portlist->next;
3498 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3499 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3500 message->param.audiopath = 1;
3501 message_put(message);
3505 /* JOIN has no pattern available */
3506 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3507 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);
3508 if (e_join_pattern) {
3509 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3511 /* disconnect our audio tx and rx */
3512 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3513 message->param.audiopath = 0;
3514 message_put(message);
3519 /* JOIN (dunno at the moment) */
3520 case MESSAGE_REMOTE_AUDIO:
3521 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);
3522 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3523 message->param.audiopath = param->channel;
3524 message_put(message);
3528 /* JOIN sends a notify message */
3529 case MESSAGE_NOTIFY:
3530 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);
3531 join_notify(portlist, message_type, param);
3534 /* JOIN wants keypad / dtmf */
3535 case MESSAGE_ENABLEKEYPAD:
3536 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);
3539 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3543 /* JOIN sends a DTMF message */
3545 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);
3546 join_dtmf(portlist, message_type, param);
3550 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);
3555 /* pick_join will connect the first incoming call found. the endpoint
3556 * will receivce a MESSAGE_CONNECT.
3558 int match_list(char *list, char *item)
3560 char *end, *next = NULL;
3562 /* no list make matching */
3567 /* eliminate white spaces */
3568 while (*list > '\0' && *list <= ' ')
3574 /* if end of list is reached, we return */
3575 if (list[0] == '\0')
3577 /* if we have more than one entry (left) */
3578 if ((end = strchr(list, ',')))
3581 next = end = strchr(list, '\0');
3582 while (*(end-1) <= ' ')
3584 /* if string part matches item */
3585 if (!strncmp(list, item, end-list))
3591 void EndpointAppPBX::pick_join(char *extensions)
3593 struct lcr_msg *message;
3594 struct port_list *portlist;
3596 class EndpointAppPBX *eapp, *found;
3598 class JoinPBX *joinpbx;
3599 struct join_relation *relation;
3602 /* find an endpoint that is ringing internally or vbox with higher priority */
3605 eapp = apppbx_first;
3607 if (eapp!=this && ea_endpoint->ep_portlist) {
3608 portlist = eapp->ea_endpoint->ep_portlist;
3610 if ((port = find_port_id(portlist->port_id))) {
3611 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3612 if (match_list(extensions, eapp->e_ext.number)) {
3618 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3619 && port->p_state==PORT_STATE_OUT_ALERTING)
3620 if (match_list(extensions, eapp->e_ext.number)) {
3624 portlist = portlist->next;
3632 /* if no endpoint found */
3634 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);
3636 set_tone(ea_endpoint->ep_portlist, "cause_10");
3637 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3638 new_state(EPOINT_STATE_OUT_DISCONNECT);
3643 if (ea_endpoint->ep_join_id) {
3644 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3647 if (!eapp->ea_endpoint->ep_join_id) {
3648 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3651 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3653 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3656 if (join->j_type != JOIN_TYPE_PBX) {
3657 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3660 joinpbx = (class JoinPBX *)join;
3661 relation = joinpbx->j_relation;
3663 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3666 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3667 relation = relation->next;
3669 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3674 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3676 if (options.deb & DEBUG_EPOINT) {
3677 class Join *debug_c = join_first;
3678 class Endpoint *debug_e = epoint_first;
3679 class Port *debug_p = port_first;
3681 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3683 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3685 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3686 debug_c = debug_c->next;
3688 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3690 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3691 debug_e = debug_e->next;
3693 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3695 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3696 debug_p = debug_p->next;
3701 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3702 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3703 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3705 /* connnecting our endpoint */
3706 new_state(EPOINT_STATE_CONNECT);
3707 if (e_ext.number[0])
3709 set_tone(ea_endpoint->ep_portlist, NULL);
3711 /* now we send a release to the ringing endpoint */
3712 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3713 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3714 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3715 message_put(message);
3717 /* we send a connect to the join with our caller id */
3718 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3719 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3720 message->param.connectinfo.present = e_callerinfo.present;
3721 message->param.connectinfo.screen = e_callerinfo.screen;
3722 message->param.connectinfo.itype = e_callerinfo.itype;
3723 message->param.connectinfo.ntype = e_callerinfo.ntype;
3724 message_put(message);
3726 /* we send a connect to our port with the remote callerid */
3727 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3728 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3729 message->param.connectinfo.present = eapp->e_callerinfo.present;
3730 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3731 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3732 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3733 /* handle restricted caller ids */
3734 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);
3735 /* display callerid if desired for extension */
3736 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));
3737 message_put(message);
3739 /* we send a connect to the audio path (not for vbox) */
3740 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3741 message->param.audiopath = 1;
3742 message_put(message);
3744 /* beeing paranoid, we make call update */
3745 trigger_work(&joinpbx->j_updatebridge);
3747 if (options.deb & DEBUG_EPOINT) {
3748 class Join *debug_c = join_first;
3749 class Endpoint *debug_e = epoint_first;
3750 class Port *debug_p = port_first;
3752 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3754 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3756 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3757 debug_c = debug_c->next;
3759 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3761 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3762 debug_e = debug_e->next;
3764 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3766 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3767 debug_p = debug_p->next;
3773 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3775 void EndpointAppPBX::join_join(void)
3777 struct lcr_msg *message;
3778 struct join_relation *our_relation, *other_relation;
3779 struct join_relation **our_relation_pointer, **other_relation_pointer;
3780 class Join *our_join, *other_join;
3781 class JoinPBX *our_joinpbx, *other_joinpbx;
3782 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3783 class Port *our_port, *other_port;
3784 class Pdss1 *our_pdss1, *other_pdss1;
3786 /* are we a candidate to join a join? */
3787 our_join = find_join_id(ea_endpoint->ep_join_id);
3789 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3792 if (our_join->j_type != JOIN_TYPE_PBX) {
3793 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3796 our_joinpbx = (class JoinPBX *)our_join;
3797 if (!ea_endpoint->ep_portlist) {
3798 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3801 if (!e_ext.number[0]) {
3802 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3805 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3807 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3810 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3811 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3814 our_pdss1 = (class Pdss1 *)our_port;
3816 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3817 other_eapp = apppbx_first;
3819 if (other_eapp == this) {
3820 other_eapp = other_eapp->next;
3823 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);
3824 if (other_eapp->e_ext.number[0] /* has terminal */
3825 && other_eapp->ea_endpoint->ep_portlist /* has port */
3826 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3827 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3828 if (other_port) { /* port still exists */
3829 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3830 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3831 other_pdss1 = (class Pdss1 *)other_port;
3832 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);
3833 if (other_pdss1->p_m_hold /* port is on hold */
3834 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3835 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3838 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3841 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3844 other_eapp = other_eapp->next;
3847 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3850 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3852 /* if we have the same join */
3853 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3854 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3857 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3859 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3862 if (other_join->j_type != JOIN_TYPE_PBX) {
3863 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3866 other_joinpbx = (class JoinPBX *)other_join;
3867 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3868 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3872 /* remove relation to endpoint for join on hold */
3873 other_relation = other_joinpbx->j_relation;
3874 other_relation_pointer = &other_joinpbx->j_relation;
3875 while(other_relation) {
3876 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3877 /* detach other endpoint on hold */
3878 *other_relation_pointer = other_relation->next;
3879 FREE(other_relation, sizeof(struct join_relation));
3881 other_relation = *other_relation_pointer;
3882 other_eapp->ea_endpoint->ep_join_id = 0;
3886 /* change join/hold pointer of endpoint to the new join */
3887 temp_epoint = find_epoint_id(other_relation->epoint_id);
3889 if (temp_epoint->ep_join_id == other_join->j_serial)
3890 temp_epoint->ep_join_id = our_join->j_serial;
3893 other_relation_pointer = &other_relation->next;
3894 other_relation = other_relation->next;
3896 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3898 /* join call relations */
3899 our_relation = our_joinpbx->j_relation;
3900 our_relation_pointer = &our_joinpbx->j_relation;
3901 while(our_relation) {
3902 our_relation_pointer = &our_relation->next;
3903 our_relation = our_relation->next;
3905 *our_relation_pointer = other_joinpbx->j_relation;
3906 other_joinpbx->j_relation = NULL;
3907 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3909 /* release endpoint on hold */
3910 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3911 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3912 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3913 message_put(message);
3915 /* if we are not a partyline, we get partyline state from other join */
3916 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3918 /* remove empty join */
3920 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3922 /* mixer must update */
3923 trigger_work(&our_joinpbx->j_updatebridge);
3925 /* we send a retrieve to that endpoint */
3926 // mixer will update the hold-state of the join and send it to the endpoints is changes
3930 /* check if we have an external call
3931 * this is used to check for encryption ability
3933 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3935 struct join_relation *relation;
3937 class JoinPBX *joinpbx;
3938 class Endpoint *epoint;
3940 /* some paranoia check */
3941 if (!ea_endpoint->ep_portlist) {
3942 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3943 *errstr = "No Call";
3946 if (!e_ext.number[0]) {
3947 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3948 *errstr = "No Call";
3952 /* check if we have a join with 2 parties */
3953 join = find_join_id(ea_endpoint->ep_join_id);
3955 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3956 *errstr = "No Call";
3959 if (join->j_type != JOIN_TYPE_PBX) {
3960 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3961 *errstr = "No PBX Call";
3964 joinpbx = (class JoinPBX *)join;
3965 relation = joinpbx->j_relation;
3967 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3968 *errstr = "No Call";
3971 if (!relation->next) {
3972 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3973 *errstr = "No Call";
3976 if (relation->next->next) {
3977 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3978 *errstr = "Err: Conference";
3981 if (relation->epoint_id == ea_endpoint->ep_serial) {
3982 relation = relation->next;
3983 if (relation->epoint_id == ea_endpoint->ep_serial) {
3984 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
3985 *errstr = "Software Error";
3990 /* check remote port for external call */
3991 epoint = find_epoint_id(relation->epoint_id);
3993 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
3994 *errstr = "No Call";
3997 if (!epoint->ep_portlist) {
3998 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
3999 *errstr = "No Call";
4002 *port = find_port_id(epoint->ep_portlist->port_id);
4004 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4005 *errstr = "No Call";
4008 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4009 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4010 *errstr = "No Ext Call";
4013 if ((*port)->p_state != PORT_STATE_CONNECT) {
4014 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4015 *errstr = "No Ext Connect";
4021 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4023 const char *logtext = "unknown";
4026 switch(message_type) {
4028 trace_header("SETUP", dir);
4029 if (dir == DIRECTION_OUT)
4030 add_trace("to", NULL, "CH(%lu)", port_id);
4031 if (dir == DIRECTION_IN)
4032 add_trace("from", NULL, "CH(%lu)", port_id);
4033 if (param->setup.callerinfo.extension[0])
4034 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4035 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4036 switch(param->setup.callerinfo.present) {
4037 case INFO_PRESENT_RESTRICTED:
4038 add_trace("caller id", "present", "restricted");
4040 case INFO_PRESENT_ALLOWED:
4041 add_trace("caller id", "present", "allowed");
4044 add_trace("caller id", "present", "not available");
4046 if (param->setup.callerinfo.ntype2) {
4047 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4048 switch(param->setup.callerinfo.present) {
4049 case INFO_PRESENT_RESTRICTED:
4050 add_trace("caller id2", "present", "restricted");
4052 case INFO_PRESENT_ALLOWED:
4053 add_trace("caller id2", "present", "allowed");
4056 add_trace("caller id2", "present", "not available");
4059 if (param->setup.redirinfo.id[0]) {
4060 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4061 switch(param->setup.redirinfo.present) {
4062 case INFO_PRESENT_RESTRICTED:
4063 add_trace("redir'ing", "present", "restricted");
4065 case INFO_PRESENT_ALLOWED:
4066 add_trace("redir'ing", "present", "allowed");
4069 add_trace("redir'ing", "present", "not available");
4072 if (param->setup.dialinginfo.id[0])
4073 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4074 if (param->setup.dialinginfo.keypad[0])
4075 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4076 if (param->setup.dialinginfo.display[0])
4077 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4078 if (param->setup.dialinginfo.sending_complete)
4079 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4083 case MESSAGE_OVERLAP:
4084 trace_header("SETUP ACKNOWLEDGE", 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_PROCEEDING:
4093 trace_header("PROCEEDING", 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_ALERTING:
4102 trace_header("ALERTING", 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);
4110 case MESSAGE_CONNECT:
4111 trace_header("CONNECT", dir);
4112 if (dir == DIRECTION_OUT)
4113 add_trace("to", NULL, "CH(%lu)", port_id);
4114 if (dir == DIRECTION_IN)
4115 add_trace("from", NULL, "CH(%lu)", port_id);
4116 if (param->connectinfo.extension[0])
4117 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4118 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4119 switch(param->connectinfo.present) {
4120 case INFO_PRESENT_RESTRICTED:
4121 add_trace("connect id", "present", "restricted");
4123 case INFO_PRESENT_ALLOWED:
4124 add_trace("connect id", "present", "allowed");
4127 add_trace("connect id", "present", "not available");
4129 if (param->connectinfo.display[0])
4130 add_trace("display", NULL, "%s", param->connectinfo.display);
4134 case MESSAGE_DISCONNECT:
4135 case MESSAGE_RELEASE:
4136 if (message_type == MESSAGE_DISCONNECT)
4137 trace_header("DISCONNECT", dir);
4139 trace_header("RELEASE", dir);
4140 if (dir == DIRECTION_OUT)
4141 add_trace("to", NULL, "CH(%lu)", port_id);
4142 if (dir == DIRECTION_IN)
4143 add_trace("from", NULL, "CH(%lu)", port_id);
4144 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4145 switch(param->disconnectinfo.location) {
4147 add_trace("cause", "location", "0-User");
4149 case LOCATION_PRIVATE_LOCAL:
4150 add_trace("cause", "location", "1-Local-PBX");
4152 case LOCATION_PUBLIC_LOCAL:
4153 add_trace("cause", "location", "2-Local-Exchange");
4155 case LOCATION_TRANSIT:
4156 add_trace("cause", "location", "3-Transit");
4158 case LOCATION_PUBLIC_REMOTE:
4159 add_trace("cause", "location", "4-Remote-Exchange");
4161 case LOCATION_PRIVATE_REMOTE:
4162 add_trace("cause", "location", "5-Remote-PBX");
4164 case LOCATION_INTERNATIONAL:
4165 add_trace("cause", "location", "7-International-Exchange");
4167 case LOCATION_BEYOND:
4168 add_trace("cause", "location", "10-Beyond-Interworking");
4171 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4173 if (param->disconnectinfo.display[0])
4174 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4178 case MESSAGE_NOTIFY:
4179 switch(param->notifyinfo.notify) {
4184 logtext = "USER_SUSPENDED";
4187 logtext = "BEARER_SERVICE_CHANGED";
4190 logtext = "USER_RESUMED";
4193 logtext = "CONFERENCE_ESTABLISHED";
4196 logtext = "CONFERENCE_DISCONNECTED";
4199 logtext = "OTHER_PARTY_ADDED";
4202 logtext = "ISOLATED";
4205 logtext = "REATTACHED";
4208 logtext = "OTHER_PARTY_ISOLATED";
4211 logtext = "OTHER_PARTY_REATTACHED";
4214 logtext = "OTHER_PARTY_SPLIT";
4217 logtext = "OTHER_PARTY_DISCONNECTED";
4220 logtext = "CONFERENCE_FLOATING";
4223 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4226 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4229 logtext = "CALL_IS_A_WAITING_CALL";
4232 logtext = "DIVERSION_ACTIVATED";
4235 logtext = "RESERVED_CT_1";
4238 logtext = "RESERVED_CT_2";
4241 logtext = "REVERSE_CHARGING";
4244 logtext = "REMOTE_HOLD";
4247 logtext = "REMOTE_RETRIEVAL";
4250 logtext = "CALL_IS_DIVERTING";
4253 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4257 trace_header("NOTIFY", dir);
4258 if (dir == DIRECTION_OUT)
4259 add_trace("to", NULL, "CH(%lu)", port_id);
4260 if (dir == DIRECTION_IN)
4261 add_trace("from", NULL, "CH(%lu)", port_id);
4262 if (param->notifyinfo.notify)
4263 add_trace("indicator", NULL, "%s", logtext);
4264 if (param->notifyinfo.id[0]) {
4265 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4266 switch(param->notifyinfo.present) {
4267 case INFO_PRESENT_RESTRICTED:
4268 add_trace("redir'on", "present", "restricted");
4270 case INFO_PRESENT_ALLOWED:
4271 add_trace("redir'on", "present", "allowed");
4274 add_trace("redir'on", "present", "not available");
4277 if (param->notifyinfo.display[0])
4278 add_trace("display", NULL, "%s", param->notifyinfo.display);
4282 case MESSAGE_PROGRESS:
4283 switch(param->progressinfo.progress) {
4285 logtext = "Call is not end to end ISDN";
4288 logtext = "Destination address is non-ISDN";
4291 logtext = "Origination address is non-ISDN";
4294 logtext = "Call has returned to the ISDN";
4297 logtext = "In-band info or pattern available";
4300 SPRINT(buffer, "%d", param->progressinfo.progress);
4304 trace_header("PROGRESS", dir);
4305 if (dir == DIRECTION_OUT)
4306 add_trace("to", NULL, "CH(%lu)", port_id);
4307 if (dir == DIRECTION_IN)
4308 add_trace("from", NULL, "CH(%lu)", port_id);
4309 add_trace("indicator", NULL, "%s", logtext);
4310 switch(param->progressinfo.location) {
4312 add_trace("cause", "location", "0-User");
4314 case LOCATION_PRIVATE_LOCAL:
4315 add_trace("cause", "location", "1-Local-PBX");
4317 case LOCATION_PUBLIC_LOCAL:
4318 add_trace("cause", "location", "2-Local-Exchange");
4320 case LOCATION_TRANSIT:
4321 add_trace("cause", "location", "3-Transit");
4323 case LOCATION_PUBLIC_REMOTE:
4324 add_trace("cause", "location", "4-Remote-Exchange");
4326 case LOCATION_PRIVATE_REMOTE:
4327 add_trace("cause", "location", "5-Remote-PBX");
4329 case LOCATION_INTERNATIONAL:
4330 add_trace("cause", "location", "7-International-Exchange");
4332 case LOCATION_BEYOND:
4333 add_trace("cause", "location", "10-Beyond-Interworking");
4336 add_trace("cause", "location", "%d", param->progressinfo.location);
4341 case MESSAGE_INFORMATION:
4342 trace_header("INFORMATION", dir);
4343 if (dir == DIRECTION_OUT)
4344 add_trace("to", NULL, "CH(%lu)", port_id);
4345 if (dir == DIRECTION_IN)
4346 add_trace("from", NULL, "CH(%lu)", port_id);
4347 if (param->information.id[0])
4348 add_trace("dialing", NULL, "%s", param->information.id);
4349 if (param->information.display[0])
4350 add_trace("display", NULL, "%s", param->information.display);
4351 if (param->information.sending_complete)
4352 add_trace("complete", NULL, "true", param->information.sending_complete);
4356 case MESSAGE_FACILITY:
4357 trace_header("FACILITY", 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);
4366 trace_header("TONE", dir);
4367 if (dir == DIRECTION_OUT)
4368 add_trace("to", NULL, "CH(%lu)", port_id);
4369 if (dir == DIRECTION_IN)
4370 add_trace("from", NULL, "CH(%lu)", port_id);
4371 if (param->tone.name[0]) {
4372 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4373 add_trace("name", NULL, "%s", param->tone.name);
4375 add_trace("off", NULL, NULL);
4379 case MESSAGE_SUSPEND:
4380 case MESSAGE_RESUME:
4381 if (message_type == MESSAGE_SUSPEND)
4382 trace_header("SUSPEND", dir);
4384 trace_header("RESUME", dir);
4385 if (dir == DIRECTION_OUT)
4386 add_trace("to", NULL, "CH(%lu)", port_id);
4387 if (dir == DIRECTION_IN)
4388 add_trace("from", NULL, "CH(%lu)", port_id);
4389 if (param->parkinfo.len)
4390 add_trace("length", NULL, "%d", param->parkinfo.len);
4395 case MESSAGE_BCHANNEL:
4396 trace_header("BCHANNEL", dir);
4397 switch(param->bchannel.type) {
4398 case BCHANNEL_REQUEST:
4399 add_trace("type", NULL, "request");
4401 case BCHANNEL_ASSIGN:
4402 add_trace("type", NULL, "assign");
4404 case BCHANNEL_ASSIGN_ACK:
4405 add_trace("type", NULL, "assign_ack");
4407 case BCHANNEL_REMOVE:
4408 add_trace("type", NULL, "remove");
4410 case BCHANNEL_REMOVE_ACK:
4411 add_trace("type", NULL, "remove_ack");
4414 if (param->bchannel.addr)
4415 add_trace("address", NULL, "%x", param->bchannel.addr);
4421 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4425 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4427 struct lcr_msg *message;
4431 if (!portlist->port_id)
4434 if (!e_connectedmode) {
4435 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4436 message->param.disconnectinfo.cause = cause;
4437 message->param.disconnectinfo.location = location;
4439 SCPY(message->param.disconnectinfo.display, display);
4441 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4443 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4445 SCPY(message->param.notifyinfo.display, display);
4447 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4449 message_put(message);
4450 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);