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;
34 memset(&e_crypt_handler, 0, sizeof(e_crypt_handler));
35 add_timer(&e_crypt_handler, crypt_handler, this, 0);
37 memset(&e_vbox_refresh, 0, sizeof(e_vbox_refresh));
38 add_timer(&e_vbox_refresh, vbox_refresh, this, 0);
39 memset(&e_action_timeout, 0, sizeof(e_action_timeout));
40 add_timer(&e_action_timeout, action_timeout, this, 0);
41 memset(&e_match_timeout, 0, sizeof(e_match_timeout));
42 add_timer(&e_match_timeout, match_timeout, this, 0);
43 memset(&e_redial_timeout, 0, sizeof(e_redial_timeout));
44 add_timer(&e_redial_timeout, redial_timeout, this, 0);
45 memset(&e_powerdial_timeout, 0, sizeof(e_powerdial_timeout));
46 add_timer(&e_powerdial_timeout, powerdial_timeout, this, 0);
47 memset(&e_cfnr_timeout, 0, sizeof(e_cfnr_timeout));
48 add_timer(&e_cfnr_timeout, cfnr_timeout, this, 0);
49 memset(&e_cfnr_call_timeout, 0, sizeof(e_cfnr_call_timeout));
50 add_timer(&e_cfnr_call_timeout, cfnr_call_timeout, this, 0);
51 memset(&e_callback_timeout, 0, sizeof(e_callback_timeout));
52 add_timer(&e_callback_timeout, callback_timeout, this, 0);
53 memset(&e_password_timeout, 0, sizeof(e_password_timeout));
54 add_timer(&e_password_timeout, password_timeout, this, 0);
57 /* add application to chain */
59 apppointer = &apppbx_first;
61 apppointer = &((*apppointer)->next);
65 memset(&e_ext, 0, sizeof(struct extension));
66 // *************** NOTE: also change value in read_extension() **************
67 e_ext.rights = 4; /* international */
68 e_ext.rx_gain = e_ext.tx_gain = 0;
69 e_state = EPOINT_STATE_IDLE;
70 e_ext.number[0] = '\0';
71 e_extension_interface[0] = '\0';
72 memset(&e_callerinfo, 0, sizeof(struct caller_info));
73 memset(&e_dialinginfo, 0, sizeof(struct dialing_info));
74 memset(&e_connectinfo, 0, sizeof(struct connect_info));
75 memset(&e_redirinfo, 0, sizeof(struct redir_info));
76 memset(&e_capainfo, 0, sizeof(struct capa_info));
77 memset(&e_rtpinfo, 0, sizeof(struct rtp_info));
80 e_ruleset = ruleset_main;
82 e_rule = e_ruleset->rule_first;
85 e_match_to_action = NULL;
87 e_extdialing = e_dialinginfo.id;
91 // e_join_tone[0] = e_hold_tone[0] = '\0';
92 e_join_pattern /*= e_hold_pattern*/ = 0;
94 e_adminid = 0; // will be set, if call was initiated via admin socket
97 e_cbdialing[0] = '\0';
100 memset(&e_callbackinfo, 0, sizeof(struct caller_info));
106 e_multipoint_cause = 0;
107 e_multipoint_location = 0;
108 e_dialing_queue[0] = '\0';
111 e_crypt_state = CM_ST_NULL;
112 e_crypt_keyengine_busy = 0;
113 e_crypt_info[0] = '\0';
117 e_tx_state = NOTIFY_STATE_ACTIVE;
118 e_rx_state = NOTIFY_STATE_ACTIVE;
119 e_join_cause = e_join_location = 0;
120 /*********************************
121 *********************************
122 ********* ATTENTION *************
123 *********************************
124 *********************************/
125 /* if you add new values, that must be initialized, also check if they must
126 * be initialized when doing callback
132 * EpointAppPBX destructor
134 EndpointAppPBX::~EndpointAppPBX(void)
136 class EndpointAppPBX *temp, **tempp;
139 del_timer(&e_crypt_handler);
141 del_timer(&e_vbox_refresh);
142 del_timer(&e_action_timeout);
143 del_timer(&e_match_timeout);
144 del_timer(&e_redial_timeout);
145 del_timer(&e_powerdial_timeout);
146 del_timer(&e_cfnr_timeout);
147 del_timer(&e_cfnr_call_timeout);
148 del_timer(&e_callback_timeout);
149 del_timer(&e_password_timeout);
153 tempp = &apppbx_first;
162 FATAL("Endpoint not in endpoint's list.\n");
169 * trace header for application
171 void EndpointAppPBX::trace_header(const char *name, int direction)
175 char msgtext[sizeof(_trace.name)];
179 /* init trace with given values */
182 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype, options.national, options.international),
186 ea_endpoint->ep_serial,
193 /* set new endpoint state
195 void EndpointAppPBX::new_state(int state)
198 if (e_state != state) {
199 trace_header("NEW STATE", DIRECTION_NONE);
200 add_trace("state", "old", "%s", state_name[e_state]);
201 add_trace("state", "new", "%s", state_name[state]);
209 /* release join and port (as specified)
211 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause, int force)
213 struct port_list *portlist;
214 struct lcr_msg *message;
217 /* message to test call */
218 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
220 /* if a release is pending */
221 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
222 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
223 if (ea_endpoint->ep_join_id) {
224 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
225 message->param.disconnectinfo.cause = joincause;
226 message->param.disconnectinfo.location = joinlocation;
227 message_put(message);
228 ea_endpoint->ep_join_id = 0;
232 if (release != RELEASE_PORT_JOINONLY) {
234 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
239 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY) {
240 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
241 while((portlist = ea_endpoint->ep_portlist)) {
242 if (portlist->port_id) {
243 SPRINT(cause, "cause_%02x", portcause);
244 set_tone(portlist, cause);
245 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
246 message->param.disconnectinfo.cause = portcause;
247 message->param.disconnectinfo.location = portlocation;
248 message->param.disconnectinfo.force = force; // set, if port should release imediately
249 message_put(message);
250 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
252 ea_endpoint->free_portlist(portlist);
255 /* if callback is enabled, call back with the given caller id */
256 if (e_callback_timeout.active) {
257 /* reset some stuff */
258 new_state(EPOINT_STATE_IDLE);
259 memset(&e_connectinfo, 0, sizeof(struct connect_info));
260 memset(&e_redirinfo, 0, sizeof(struct redir_info));
261 e_start = e_stop = 0;
262 e_ruleset = ruleset_main;
264 e_rule = e_ruleset->rule_first;
266 unsched_timer(&e_action_timeout);
267 unsched_timer(&e_match_timeout);
268 unsched_timer(&e_cfnr_timeout);
269 unsched_timer(&e_cfnr_call_timeout);
270 e_match_to_action = NULL;
272 e_extdialing = e_dialinginfo.id;
278 e_multipoint_cause = 0;
279 e_multipoint_location = 0;
280 e_dialing_queue[0] = '\0';
283 e_crypt_state = CM_ST_NULL;
284 e_crypt_keyengine_busy = 0;
285 e_crypt_info[0] = '\0';
290 e_tx_state = NOTIFY_STATE_ACTIVE;
291 e_rx_state = NOTIFY_STATE_ACTIVE;
292 e_join_cause = e_join_location = 0;
294 /* the caller info of the callback user */
295 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
296 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
297 /* create dialing by callerinfo */
298 if (e_ext.number[0] && e_extension_interface[0]) {
299 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
300 /* create callback to the current terminal */
301 SCPY(e_dialinginfo.id, e_ext.number);
302 SCPY(e_dialinginfo.interfaces, e_extension_interface);
303 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
304 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
307 SCPY(e_dialinginfo.id, e_cbto);
309 /* numberrize caller id and use it to dial to the callback */
310 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
312 e_dialinginfo.itype = INFO_ITYPE_ISDN;
313 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
314 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
319 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
320 if (--ea_endpoint->ep_use <= 0) /* when e_lock is 0, the endpoint will be deleted */
321 trigger_work(&ea_endpoint->ep_delete);
327 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
328 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
330 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");
332 /* caller id is not restricted, so we do nothing */
333 if (*present != INFO_PRESENT_RESTRICTED)
336 /* only extensions are restricted */
340 /* if we enabled anonymouse ignore */
341 if (ext->anon_ignore)
344 /* else we remove the caller id */
348 *ntype = INFO_NTYPE_UNKNOWN;
350 // *screen = INFO_SCREEN_USER;
351 // maybe we should not make voip address anonymous
354 // maybe it's no fraud to present extension id
356 // extension[0] = '\0';
361 /* used display message to display callerid as available */
362 char *EndpointAppPBX::apply_callerid_display(const char *id, int itype, int ntype, int present, int screen, const char *extension, const char *name)
364 static char display[81];
367 const char *cid = numberrize_callerinfo(id, ntype, options.national, options.international);
369 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");
378 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
380 /* internal extension's caller id */
381 if (extension[0] && e_ext.display_int) {
383 SCAT(display, extension);
386 if (itype == INFO_ITYPE_VBOX)
387 SCAT(display, "(vbox)");
389 SCAT(display, "(int)");
392 /* external caller id */
393 if (!extension[0] && e_ext.display_ext) {
396 if (present == INFO_PRESENT_RESTRICTED)
397 SCAT(display, "anonymous");
399 SCAT(display, "unknown");
406 /* display if callerid is anonymouse but available due anon-ignore */
407 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED) {
409 SCAT(display, "unknown");
412 SCAT(display, " anon");
415 /* display if callerid is anonymouse but available due anon-ignore */
416 if (e_ext.display_fake && screen==INFO_SCREEN_USER && ntype!=INFO_NTYPE_NOTPRESENT) {
419 if (present == INFO_PRESENT_RESTRICTED)
420 SCAT(display, "anonymous");
422 SCAT(display, "unknown");
427 SCAT(display, " fake");
431 if (name[0] && e_ext.display_name) {
432 if (!display[0] && cid[0])
443 * uses the current state to notify activity
445 void EndpointAppPBX::notify_active(void)
447 struct port_list *portlist = ea_endpoint->ep_portlist;
448 struct lcr_msg *message;
452 case NOTIFY_STATE_ACTIVE:
453 /* we are already active, so we don't do anything */
456 case NOTIFY_STATE_SUSPEND:
457 notify = INFO_NOTIFY_USER_RESUMED;
459 set_tone(portlist, NULL);
460 portlist = portlist->next;
462 portlist = ea_endpoint->ep_portlist;
465 case NOTIFY_STATE_HOLD:
466 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
468 set_tone(portlist, NULL);
469 portlist = portlist->next;
471 portlist = ea_endpoint->ep_portlist;
474 case NOTIFY_STATE_CONFERENCE:
475 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
477 set_tone(portlist, NULL);
478 portlist = portlist->next;
480 portlist = ea_endpoint->ep_portlist;
484 PERROR("unknown e_tx_state = %d\n", e_tx_state);
489 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
490 message->param.notifyinfo.notify = notify;
491 message_put(message);
492 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
493 portlist = portlist->next;
499 * keypad functions during call. one example to use this is to put a call on hold or start a conference
501 void EndpointAppPBX::keypad_function(char digit)
504 /* we must be in a call, in order to send messages to the call */
505 if (e_ext.number[0] == '\0') {
506 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
511 /* join conference */
513 if (ea_endpoint->ep_join_id == 0) {
514 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
517 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
524 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
528 /* crypt key-exchange */
530 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
536 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
542 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
547 /* set tone pattern for port */
548 void EndpointAppPBX::set_tone(struct port_list *portlist, const char *tone)
550 struct lcr_msg *message;
555 /* store for suspended processes */
559 if (e_join_pattern /* pattern are provided */
560 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
561 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
562 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
563 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
564 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
565 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
566 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
567 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
568 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
569 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
570 && tone[0] && !!strncmp(tone,"crypt_*",6)) {
571 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
576 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
577 SCPY(message->param.tone.dir, e_ext.tones_dir);
578 SCPY(message->param.tone.name, tone);
579 message_put(message);
580 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
582 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
587 /* hunts for the given interface
588 * it does not need to have an mISDNport instance */
589 struct interface *EndpointAppPBX::hunt_interface(char *ifname)
591 struct interface *interface;
592 int there_is_an_external = 0;
594 interface = interface_first;
596 /* first find the given interface or, if not given, one with no extension */
599 if (!there_is_an_external && !(ifname && ifname[0])) {
600 trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
601 add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
607 /* check for given interface */
608 if (ifname && ifname[0]) {
609 if (!strcasecmp(interface->name, ifname)) {
610 /* found explicit interface */
611 trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
612 add_trace("interface", NULL, "%s", ifname);
617 if (interface->external) {
618 there_is_an_external = 1;
619 /* found non extension */
620 trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
621 add_trace("interface", NULL, "%s", interface->name);
627 interface = interface->next;
637 * hunts an mISDNport that is available for an outgoing call
638 * if no ifname was given, any interface that is not an extension
641 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
643 struct interface *interface;
644 struct interface_port *ifport, *ifport_start;
645 struct select_channel *selchannel;
646 struct mISDNport *mISDNport;
648 int there_is_an_external = 0;
650 interface = interface_first;
652 /* first find the given interface or, if not given, one with no extension */
655 if (!there_is_an_external && !(ifname && ifname[0])) {
656 trace_header("CHANNEL SELECTION (no external interface specified)", DIRECTION_NONE);
657 add_trace("info", NULL, "Add 'extern' parameter to interface.conf.");
663 /* check for given interface */
664 if (ifname && ifname[0]) {
665 if (!strcasecmp(interface->name, ifname)) {
666 /* found explicit interface */
667 trace_header("CHANNEL SELECTION (found given interface)", DIRECTION_NONE);
668 add_trace("interface", NULL, "%s", ifname);
674 if (interface->external) {
675 there_is_an_external = 1;
676 /* found non extension */
677 trace_header("CHANNEL SELECTION (found external interface)", DIRECTION_NONE);
678 add_trace("interface", NULL, "%s", interface->name);
684 interface = interface->next;
688 /* see if interface has ports */
689 if (!interface->ifport) {
691 trace_header("CHANNEL SELECTION (active ports, skipping)", DIRECTION_NONE);
692 add_trace("interface", NULL, "%s", interface->name);
694 interface = interface->next;
698 /* select port by algorithm */
699 ifport_start = interface->ifport;
701 if (interface->hunt == HUNT_ROUNDROBIN) {
702 while(ifport_start->next && index<interface->hunt_next) {
703 ifport_start = ifport_start->next;
706 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
707 add_trace("port", NULL, "%d", ifport_start->portnum);
708 add_trace("position", NULL, "%d", index);
713 ifport = ifport_start;
716 /* see if port is available */
717 if (!ifport->mISDNport) {
718 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
719 add_trace("port", NULL, "%d", ifport->portnum);
720 add_trace("position", NULL, "%d", index);
724 mISDNport = ifport->mISDNport;
726 /* see if port is administratively blocked */
728 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
729 add_trace("port", NULL, "%d", ifport->portnum);
730 add_trace("position", NULL, "%d", index);
735 /* see if link is up on PTP*/
736 if (mISDNport->l2hold && mISDNport->l2link<1) {
737 trace_header("CHANNEL SELECTION (port's layer 2 is down, skipping)", DIRECTION_NONE);
738 add_trace("port", NULL, "%d", ifport->portnum);
739 add_trace("position", NULL, "%d", index);
744 /* check for channel form selection list */
747 if (mISDNport->ss5) {
749 port = ss5_hunt_line(mISDNport);
751 *channel = port->p_m_b_channel;
752 trace_header("CHANNEL SELECTION (selecting SS5 channel)", DIRECTION_NONE);
753 add_trace("port", NULL, "%d", ifport->portnum);
754 add_trace("position", NULL, "%d", index);
755 add_trace("channel", NULL, "%d", *channel);
761 selchannel = ifport->out_channel;
763 switch(selchannel->channel) {
764 case CHANNEL_FREE: /* free channel */
765 if (mISDNport->b_reserved >= mISDNport->b_num)
766 break; /* all channel in use or reserverd */
769 while(i < mISDNport->b_num) {
770 if (mISDNport->b_port[i] == NULL) {
771 *channel = i+1+(i>=15);
772 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
773 add_trace("port", NULL, "%d", ifport->portnum);
774 add_trace("position", NULL, "%d", index);
775 add_trace("channel", NULL, "%d", *channel);
783 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
784 add_trace("port", NULL, "%d", ifport->portnum);
785 add_trace("position", NULL, "%d", index);
789 case CHANNEL_ANY: /* don't ask for channel */
790 if (mISDNport->b_reserved >= mISDNport->b_num) {
791 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
792 add_trace("port", NULL, "%d", ifport->portnum);
793 add_trace("position", NULL, "%d", index);
794 add_trace("total", NULL, "%d", mISDNport->b_num);
795 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
797 break; /* all channel in use or reserverd */
799 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
800 add_trace("port", NULL, "%d", ifport->portnum);
801 add_trace("position", NULL, "%d", index);
803 *channel = CHANNEL_ANY;
806 case CHANNEL_NO: /* call waiting */
807 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
808 add_trace("port", NULL, "%d", ifport->portnum);
809 add_trace("position", NULL, "%d", index);
811 *channel = CHANNEL_NO;
815 if (selchannel->channel<1 || selchannel->channel==16) {
816 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
817 add_trace("port", NULL, "%d", ifport->portnum);
818 add_trace("position", NULL, "%d", index);
819 add_trace("channel", NULL, "%d", selchannel->channel);
821 break; /* invalid channels */
823 i = selchannel->channel-1-(selchannel->channel>=17);
824 if (i >= mISDNport->b_num) {
825 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
826 add_trace("port", NULL, "%d", ifport->portnum);
827 add_trace("position", NULL, "%d", index);
828 add_trace("channel", NULL, "%d", selchannel->channel);
829 add_trace("channels", NULL, "%d", mISDNport->b_num);
831 break; /* channel not in port */
833 if (mISDNport->b_port[i] == NULL) {
834 *channel = selchannel->channel;
835 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
836 add_trace("port", NULL, "%d", ifport->portnum);
837 add_trace("position", NULL, "%d", index);
838 add_trace("channel", NULL, "%d", *channel);
845 break; /* found channel */
846 selchannel = selchannel->next;
850 /* if channel was found, return mISDNport and channel */
852 /* setting next port to start next time */
853 if (interface->hunt == HUNT_ROUNDROBIN) {
857 interface->hunt_next = index;
863 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
864 add_trace("port", NULL, "%d", ifport->portnum);
865 add_trace("position", NULL, "%d", index);
869 /* go next port, until all ports are checked */
871 ifport = ifport->next;
874 ifport = interface->ifport;
876 if (ifport != ifport_start)
880 interface = interface->next;
884 return(NULL); /* no port found */
888 /* outgoing setup to port(s)
889 * ports will be created and a setup is sent if everything is ok. otherwhise
890 * the endpoint is destroyed.
892 void EndpointAppPBX::out_setup(int cfnr)
894 struct dialing_info dialinginfo;
896 struct port_list *portlist;
897 struct lcr_msg *message;
899 int cause = CAUSE_RESSOURCEUNAVAIL;
902 struct interface *interface;
904 struct mISDNport *mISDNport;
908 class EndpointAppPBX *atemp;
909 // char allowed_ports[256];
911 char ifname[sizeof(e_ext.interfaces)],
913 struct port_settings port_settings;
916 struct admin_list *admin;
919 int mode = B_MODE_TRANSPARENT;
921 /* set bchannel mode */
922 mode = e_capainfo.source_mode;
924 /* create settings for creating port */
925 memset(&port_settings, 0, sizeof(port_settings));
927 SCPY(port_settings.tones_dir, e_ext.tones_dir);
929 SCPY(port_settings.tones_dir, options.tones_dir);
930 port_settings.no_seconds = e_ext.no_seconds;
932 /* 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 */
934 /* check what dialinginfo.itype we got */
935 switch(e_dialinginfo.itype) {
936 /* *********************** call to extension or vbox */
937 case INFO_ITYPE_ISDN_EXTENSION:
938 /* check if we deny incoming calls when we use an extension */
939 if (e_ext.noknocking) {
940 atemp = apppbx_first;
943 if (!strcmp(atemp->e_ext.number, e_ext.number))
948 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
949 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYSPE_ join, port */
950 return; /* must exit here */
953 /* FALL THROUGH !!!! */
954 case INFO_ITYPE_VBOX:
955 /* get dialed extension's info */
956 // SCPY(exten, e_dialinginfo.id);
957 // if (strchr(exten, ','))
958 // *strchr(exten, ',') = '\0';
959 // if (!read_extension(&e_ext, exten))
960 if (!read_extension(&e_ext, e_dialinginfo.id)) {
961 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
962 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
963 return; /* must exit here */
965 e_dialinginfo.sending_complete = 1;
967 if (e_dialinginfo.itype == INFO_ITYPE_VBOX) {
968 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
973 /* string from unconditional call forward (cfu) */
976 /* present to forwarded party */
977 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
978 e_callerinfo.present = INFO_PRESENT_ALLOWED;
980 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
984 /* string from busy call forward (cfb) */
987 class EndpointAppPBX *checkapp = apppbx_first;
989 if (checkapp != this) { /* any other endpoint except our own */
990 if (!strcmp(checkapp->e_ext.number, e_ext.number)) {
991 /* present to forwarded party */
992 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
993 e_callerinfo.present = INFO_PRESENT_ALLOWED;
995 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
999 checkapp = checkapp->next;
1003 /* string from no-response call forward (cfnr) */
1006 /* when cfnr is done, out_setup() will setup the call */
1008 /* present to forwarded party */
1009 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1010 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1014 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH)) {
1015 schedule_timer(&e_cfnr_timeout, e_ext.cfnr_delay, 0);
1016 schedule_timer(&e_cfnr_call_timeout, e_ext.cfnr_delay + 1, 0); /* call one second after release */
1017 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);
1021 /* call to all internal interfaces */
1022 p = e_ext.interfaces;
1023 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1027 while(*p!=',' && *p!='\0')
1029 SCCAT(ifname, *p++);
1032 /* search interface */
1033 interface = hunt_interface(ifname);
1035 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1036 add_trace("interface", NULL, "%s", ifname);
1040 /* found interface */
1041 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
1043 if (interface->gsm_bs) {
1044 SPRINT(portname, "%s-%d-out", interface->name, 0);
1045 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1046 earlyb = (interface->is_earlyb == IS_YES);
1050 if (interface->gsm_ms) {
1051 SPRINT(portname, "%s-%d-out", interface->name, 0);
1052 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1053 earlyb = (interface->is_earlyb == IS_YES);
1057 if (interface->sip) {
1058 SPRINT(portname, "%s-%d-out", interface->name, 0);
1059 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1060 earlyb = (interface->is_earlyb == IS_YES);
1065 /* hunt for mISDNport and create Port */
1066 mISDNport = hunt_port(ifname, &channel);
1068 trace_header("INTERFACE (busy)", DIRECTION_NONE);
1069 add_trace("interface", NULL, "%s", ifname);
1074 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1077 port = ss5_hunt_line(mISDNport);
1080 if (mISDNport->ifport->remote) {
1081 admin = admin_first;
1083 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1085 admin = admin->next;
1088 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1089 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1093 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1095 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);
1096 earlyb = mISDNport->earlyb;
1098 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
1099 add_trace("interface", NULL, "%s", ifname);
1105 FATAL("Failed to create Port instance\n");
1106 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
1107 memset(&dialinginfo, 0, sizeof(dialinginfo));
1108 SCPY(dialinginfo.id, e_dialinginfo.id);
1109 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1110 dialinginfo.ntype = e_dialinginfo.ntype;
1111 /* create port_list relation */
1112 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1114 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1116 goto check_anycall_intern;
1118 /* directory.list */
1119 if (e_callerinfo.id[0] && e_ext.display_name) {
1120 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1122 SCPY(e_callerinfo.name, dirname);
1124 // dss1 = (class Pdss1 *)port;
1126 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1127 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1128 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1129 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1130 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1131 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1132 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1133 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1134 //terminal if (e_dialinginfo.id)
1135 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1136 /* handle restricted caller ids */
1137 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);
1138 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);
1139 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);
1140 /* display callerid if desired for extension */
1141 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));
1142 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1143 /* use cnip, if enabld */
1144 // if (!e_ext.centrex)
1145 // message->param.setup.callerinfo.name[0] = '\0';
1146 /* screen clip if prefix is required */
1147 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0]) {
1148 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1149 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype, options.national, options.international));
1150 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1152 if (message->param.setup.callerinfo.id2[0] && e_ext.clip_prefix[0]) {
1153 SCPY(message->param.setup.callerinfo.id2, e_ext.clip_prefix);
1154 SCAT(message->param.setup.callerinfo.id2, numberrize_callerinfo(e_callerinfo.id2,e_callerinfo.ntype2, options.national, options.international));
1155 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_UNKNOWN;
1157 /* use internal caller id */
1158 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
1159 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1160 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1161 message->param.setup.callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1163 message_put(message);
1164 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1168 /* string from parallel call forward (cfp) */
1171 if (e_ext.anon_ignore && e_callerinfo.id[0]) {
1172 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1173 e_callerinfo.present2 = INFO_PRESENT_ALLOWED;
1177 vbox_only: /* entry point for answering machine only */
1178 cfu_only: /* entry point for cfu */
1179 cfb_only: /* entry point for cfb */
1180 cfnr_only: /* entry point for cfnr */
1181 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1185 /* only if vbox should be dialed, and terminal is given */
1186 if (!strcmp(p, "vbox") && e_ext.number[0]) {
1187 /* go to the end of p */
1190 /* answering vbox call */
1191 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1193 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1194 FATAL("No memory for VBOX Port instance\n");
1195 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1196 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1199 while(*p!=',' && *p!='\0')
1204 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1206 /* hunt for mISDNport and create Port */
1207 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1209 /* creating EXTERNAL port*/
1210 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1213 port = ss5_hunt_line(mISDNport);
1216 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);
1218 FATAL("No memory for Port instance\n");
1219 earlyb = mISDNport->earlyb;
1224 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1225 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1230 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1231 goto check_anycall_intern;
1233 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1234 memset(&dialinginfo, 0, sizeof(dialinginfo));
1235 SCPY(dialinginfo.id, cfp);
1236 dialinginfo.itype = INFO_ITYPE_ISDN;
1237 dialinginfo.ntype = e_dialinginfo.ntype;
1238 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1240 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1242 goto check_anycall_intern;
1244 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1245 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1246 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1247 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1248 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1249 /* if clip is hidden */
1250 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT) {
1251 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1252 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1253 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1254 message->param.setup.callerinfo.present = e_ext.callerid_present;
1255 message->param.setup.callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
1257 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1258 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1259 //terminal if (e_dialinginfo.id)
1260 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1261 /* handle restricted caller ids */
1262 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);
1263 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);
1264 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);
1265 /* display callerid if desired for extension */
1266 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));
1267 message_put(message);
1268 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1272 check_anycall_intern:
1273 /* now we have all ports created */
1275 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1277 if (!ea_endpoint->ep_join_id)
1279 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1280 return; /* must exit here */
1284 /* *********************** external call */
1286 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: called='%s' keypad='%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, e_dialinginfo.keypad);
1287 /* call to extenal interfaces */
1288 if (e_dialinginfo.keypad[0])
1289 p = e_dialinginfo.keypad;
1291 p = e_dialinginfo.id;
1295 while(*p!=',' && *p!='\0')
1296 SCCAT(number, *p++);
1300 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");
1301 /* search interface */
1302 interface = hunt_interface(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL);
1304 trace_header("INTERFACE (not found)", DIRECTION_NONE);
1305 add_trace("interface", NULL, "%s", ifname);
1307 goto check_anycall_extern;
1309 /* found interface */
1311 if (interface->gsm_bs) {
1312 SPRINT(portname, "%s-%d-out", interface->name, 0);
1313 port = new Pgsm_bs(PORT_TYPE_GSM_BS_OUT, portname, &port_settings, interface);
1314 earlyb = (interface->is_earlyb == IS_YES);
1318 if (interface->gsm_ms) {
1319 SPRINT(portname, "%s-%d-out", interface->name, 0);
1320 port = new Pgsm_ms(PORT_TYPE_GSM_MS_OUT, portname, &port_settings, interface);
1321 earlyb = (interface->is_earlyb == IS_YES);
1325 if (interface->sip) {
1326 SPRINT(portname, "%s-%d-out", interface->name, 0);
1327 port = new Psip(PORT_TYPE_SIP_OUT, portname, &port_settings, interface);
1328 earlyb = (interface->is_earlyb == IS_YES);
1333 /* hunt for mISDNport and create Port */
1334 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1336 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1337 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1339 goto check_anycall_extern;
1341 /* creating EXTERNAL port*/
1342 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1345 port = ss5_hunt_line(mISDNport);
1348 if (mISDNport->ifport->remote) {
1349 admin = admin_first;
1351 if (admin->remote_name[0] && !strcmp(admin->remote_name, mISDNport->ifport->remote_app))
1353 admin = admin->next;
1356 trace_header("INTERFACE (remote not connected)", DIRECTION_NONE);
1357 add_trace("application", NULL, "%s", mISDNport->ifport->remote_app);
1361 port = new Premote(PORT_TYPE_REMOTE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode, admin->sock);
1363 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);
1364 earlyb = mISDNport->earlyb;
1366 trace_header("INTERFACE (has no function)", DIRECTION_NONE);
1367 add_trace("interface", NULL, "%s", ifname);
1373 FATAL("No memory for Port instance\n");
1374 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1375 memset(&dialinginfo, 0, sizeof(dialinginfo));
1376 if (e_dialinginfo.keypad[0])
1377 SCPY(dialinginfo.keypad, number);
1379 SCPY(dialinginfo.id, number);
1380 dialinginfo.itype = INFO_ITYPE_ISDN;
1381 dialinginfo.ntype = e_dialinginfo.ntype;
1382 dialinginfo.sending_complete = e_dialinginfo.sending_complete;
1383 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1385 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1387 goto check_anycall_extern;
1389 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1390 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1391 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1392 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1393 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1394 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1395 memcpy(&message->param.setup.rtpinfo, &e_rtpinfo, sizeof(struct rtp_info));
1396 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1397 //terminal if (e_dialinginfo.id)
1398 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1399 /* handle restricted caller ids */
1400 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);
1401 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);
1402 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);
1403 /* display callerid if desired for extension */
1404 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));
1405 message_put(message);
1406 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1410 check_anycall_extern:
1411 /* now we have all ports created */
1413 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1415 if (!ea_endpoint->ep_join_id)
1417 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1418 return; /* must exit here */
1425 int action_timeout(struct lcr_timer *timer, void *instance, int index)
1427 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1429 if (!ea->e_action || ea->e_state == EPOINT_STATE_CONNECT)
1432 unsched_timer(&ea->e_redial_timeout);
1433 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea->ea_endpoint->ep_serial);
1434 ea->e_multipoint_cause = 0;
1435 ea->e_multipoint_location = 0;
1436 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1437 ea->e_join_pattern = 0;
1438 ea->process_dialing(1);
1439 /* we must exit, because our endpoint might be gone */
1444 int match_timeout(struct lcr_timer *timer, void *instance, int index)
1446 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1448 if (!ea->e_action) {
1449 unsched_timer(&ea->e_redial_timeout);
1450 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea->ea_endpoint->ep_serial);
1451 ea->process_dialing(0);
1452 /* we must exit, because our endpoint might be gone */
1458 int redial_timeout(struct lcr_timer *timer, void *instance, int index)
1460 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1462 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea->ea_endpoint->ep_serial);
1464 ea->new_state(EPOINT_STATE_OUT_SETUP);
1465 /* call special setup routine */
1471 int powerdial_timeout(struct lcr_timer *timer, void *instance, int index)
1473 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1475 /* leave power dialing on */
1476 ea->e_powerdial_on = 1;
1477 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea->ea_endpoint->ep_serial);
1480 ea->e_ruleset = ruleset_main;
1482 ea->e_rule = ea->e_ruleset->rule_first;
1483 ea->e_action = NULL;
1484 ea->new_state(EPOINT_STATE_IN_OVERLAP);
1485 ea->process_dialing(0);
1490 int cfnr_timeout(struct lcr_timer *timer, void *instance, int index)
1492 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1493 struct port_list *portlist;
1494 struct lcr_msg *message;
1496 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea->ea_endpoint->ep_serial);
1498 /* release all ports */
1499 while((portlist = ea->ea_endpoint->ep_portlist)) {
1500 message = message_create(ea->ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1501 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1502 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1503 message_put(message);
1504 ea->logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1505 ea->ea_endpoint->free_portlist(portlist);
1508 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1509 message->param.audiopath = 0;
1510 message_put(message);
1511 /* indicate no patterns */
1512 message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1513 message_put(message);
1514 /* set setup state, since we have no response from the new join */
1515 ea->new_state(EPOINT_STATE_OUT_SETUP);
1520 int cfnr_call_timeout(struct lcr_timer *timer, void *instance, int index)
1522 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1524 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);
1530 int callback_timeout(struct lcr_timer *timer, void *instance, int index)
1532 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1534 if (ea->e_state == EPOINT_STATE_IDLE) {
1535 /* epoint is idle, check callback */
1536 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea->ea_endpoint->ep_serial);
1537 ea->new_state(EPOINT_STATE_OUT_SETUP);
1544 int password_timeout(struct lcr_timer *timer, void *instance, int index)
1546 class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
1548 if (ea->e_action->index==ACTION_PASSWORD || ea->e_action->index==ACTION_PASSWORD_WRITE) {
1549 struct port_list *portlist;
1551 ea->e_ruleset = ruleset_main;
1553 ea->e_rule = ea->e_ruleset->rule_first;
1554 ea->e_action = NULL;
1555 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea->ea_endpoint->ep_serial, ea->e_extdialing);
1556 ea->trace_header("PASSWORD timeout", DIRECTION_NONE);
1558 ea->e_connectedmode = 0;
1560 ea->new_state(EPOINT_STATE_OUT_DISCONNECT);
1561 portlist = ea->ea_endpoint->ep_portlist;
1563 ea->message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1564 ea->set_tone(portlist, "cause_10");
1571 /* doing a hookflash */
1572 void EndpointAppPBX::hookflash(void)
1577 /* be sure that we are active */
1579 e_tx_state = NOTIFY_STATE_ACTIVE;
1581 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1583 if (ea_endpoint->ep_use > 1) {
1584 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1587 /* dialtone after pressing the hash key */
1588 process_hangup(e_join_cause, e_join_location);
1589 e_multipoint_cause = 0;
1590 e_multipoint_location = 0;
1591 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1593 port->set_echotest(0);
1595 if (ea_endpoint->ep_join_id) {
1596 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
1598 e_ruleset = ruleset_main;
1600 e_rule = e_ruleset->rule_first;
1602 new_state(EPOINT_STATE_IN_OVERLAP);
1603 e_connectedmode = 1;
1604 SCPY(e_dialinginfo.id, e_ext.prefix);
1605 e_extdialing = e_dialinginfo.id;
1607 if (e_dialinginfo.id[0]) {
1608 set_tone(ea_endpoint->ep_portlist, "dialing");
1611 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1619 /* messages from port
1621 /* port MESSAGE_SETUP */
1622 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1624 struct lcr_msg *message;
1626 int writeext; /* flags need to write extension after modification */
1629 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1631 portlist->port_type = param->setup.port_type;
1632 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1633 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1634 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1635 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1636 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
1638 /* convert (inter-)national number type */
1639 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_dialinginfo.id, e_dialinginfo.ntype, options.national, options.international));
1640 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
1642 // e_dtmf = param->setup.dtmf;
1643 /* screen incoming caller id */
1644 if (e_callerinfo.interface[0]) {
1645 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, e_callerinfo.interface);
1646 do_screen(0, e_callerinfo.id2, sizeof(e_callerinfo.id2), &e_callerinfo.ntype2, &e_callerinfo.present2, e_callerinfo.interface);
1649 /* process extension */
1650 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1651 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1652 /* port makes call from extension */
1653 SCPY(e_callerinfo.extension, e_callerinfo.id);
1654 SCPY(e_ext.number, e_callerinfo.extension);
1655 SCPY(e_extension_interface, e_callerinfo.interface);
1657 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1660 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION) {
1661 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1663 /* get extension's info about caller */
1664 if (!read_extension(&e_ext, e_ext.number)) {
1665 /* extension doesn't exist */
1666 trace_header("EXTENSION (not created)", DIRECTION_IN);
1667 add_trace("extension", NULL, "%s", e_ext.number);
1669 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1670 new_state(EPOINT_STATE_OUT_DISCONNECT);
1671 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1672 e_ext.number[0] = '\0'; /* no terminal */
1677 /* put prefix (next) in front of e_dialinginfo.id */
1678 if (e_ext.next[0]) {
1679 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1680 SCPY(e_dialinginfo.id, buffer);
1681 e_ext.next[0] = '\0';
1683 } else if (e_ext.prefix[0]) {
1684 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1685 SCPY(e_dialinginfo.id, buffer);
1688 /* screen caller id by extension's config */
1689 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1691 SCPY(e_callerinfo.name, e_ext.name);
1692 /* use caller id (or if exist: id_next_call) for this call */
1693 if (e_ext.id_next_call_present >= 0) {
1694 SCPY(e_callerinfo.id, e_ext.id_next_call);
1695 /* if we restrict the pesentation */
1696 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1697 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1698 else e_callerinfo.present = e_ext.id_next_call_present;
1699 e_callerinfo.ntype = e_ext.id_next_call_type;
1700 e_ext.id_next_call_present = -1;
1703 SCPY(e_callerinfo.id, e_ext.callerid);
1704 /* if we restrict the pesentation */
1705 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1706 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1707 else e_callerinfo.present = e_ext.callerid_present;
1708 e_callerinfo.ntype = e_ext.callerid_type;
1710 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
1712 /* extension is written */
1714 write_extension(&e_ext, e_ext.number);
1716 /* set volume of rx and tx */
1717 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1718 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
1719 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1720 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1721 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1722 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1723 message_put(message);
1726 /* start recording if enabled */
1727 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO)) {
1728 /* check if we are a terminal */
1729 if (e_ext.number[0] == '\0')
1730 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1732 port = find_port_id(portlist->port_id);
1734 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1738 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1739 /* no terminal identification */
1740 e_ext.number[0] = '\0';
1741 e_extension_interface[0] = '\0';
1742 memset(&e_ext, 0, sizeof(e_ext));
1743 e_ext.rights = 4; /* right to dial internat */
1747 e_ruleset = ruleset_main;
1749 e_rule = e_ruleset->rule_first;
1751 e_extdialing = e_dialinginfo.id;
1752 new_state(EPOINT_STATE_IN_SETUP);
1753 if (e_dialinginfo.id[0]) {
1754 set_tone(portlist, "dialing");
1756 if (e_ext.number[0])
1757 set_tone(portlist, "dialpbx");
1759 set_tone(portlist, "dialtone");
1762 if (e_state == EPOINT_STATE_IN_SETUP) {
1763 /* request MORE info, if not already at higher state */
1764 new_state(EPOINT_STATE_IN_OVERLAP);
1765 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1766 message_put(message);
1767 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1771 /* port MESSAGE_INFORMATION */
1772 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1774 struct lcr_msg *message;
1776 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1778 /* ignore information message without digit information */
1779 if (!param->information.id[0])
1784 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1786 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1791 /* if vbox_play is done, the information are just used as they come */
1793 if (e_action->index == ACTION_VBOX_PLAY) {
1794 /* concat dialing string */
1795 SCAT(e_dialinginfo.id, param->information.id);
1800 /* keypad when disconnect but in connected mode */
1801 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode) {
1802 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1803 /* processing keypad function */
1804 if (param->information.id[0] == '0') {
1810 /* keypad when connected */
1811 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1812 if (e_enablekeypad) {
1813 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1814 memcpy(&message->param, param, sizeof(union parameter));
1815 message_put(message);
1819 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1820 /* processing keypad function */
1821 if (param->information.id[0] == '0') {
1824 if (param->information.id[0])
1825 keypad_function(param->information.id[0]);
1827 if (e_ext.number[0])
1828 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1830 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1835 if (e_state != EPOINT_STATE_IN_OVERLAP) {
1836 if (e_ext.number[0])
1837 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1839 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1843 if (!param->information.id[0])
1845 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1846 set_tone(portlist, "dialing");
1849 if (e_action->index==ACTION_OUTDIAL
1850 || e_action->index==ACTION_EXTERNAL
1851 || e_action->index==ACTION_REMOTE) {
1853 set_tone(portlist, "dialing");
1854 else if (!e_extdialing[0])
1855 set_tone(portlist, "dialing");
1857 /* concat dialing string */
1858 SCAT(e_dialinginfo.id, param->information.id);
1862 /* port MESSAGE_DTMF */
1863 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1866 struct lcr_msg *message;
1870 /* only if dtmf detection is enabled */
1872 trace_header("DTMF (disabled)", DIRECTION_IN);
1876 trace_header("DTMF", DIRECTION_IN);
1877 add_trace("digit", NULL, "%c", param->dtmf);
1881 NOTE: vbox is now handled due to overlap state
1882 /* if vbox_play is done, the dtmf digits are just used as they come */
1884 if (e_action->index == ACTION_VBOX_PLAY) {
1885 /* concat dialing string */
1886 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1887 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1888 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1891 /* continue to process *X# sequences */
1895 /* check for *X# sequence */
1896 if (e_state == EPOINT_STATE_CONNECT || e_state == EPOINT_STATE_IN_ALERTING) {
1897 if (e_enablekeypad) {
1898 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1899 memcpy(&message->param, param, sizeof(union parameter));
1900 message_put(message);
1903 if (e_dtmf_time+3 < now) {
1904 /* the last digit was too far in the past to be a sequence */
1905 if (param->dtmf == '*')
1906 /* only start is allowed in the sequence */
1911 /* we have a sequence of digits, see what we got */
1912 if (param->dtmf == '*')
1914 else if (param->dtmf>='0' && param->dtmf<='9') {
1915 /* we need to have a star before we receive the digit of the sequence */
1916 if (e_dtmf_last == '*')
1917 e_dtmf_last = param->dtmf;
1918 } else if (param->dtmf == '#') {
1920 if (e_dtmf_last>='0' && e_dtmf_last<='9') {
1921 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1922 if (e_dtmf_last == '0') {
1926 /* processing keypad function */
1928 keypad_function(e_dtmf_last);
1934 /* set last time of dtmf */
1939 /* check for ## hookflash during dialing */
1941 if (e_action->index==ACTION_PASSWORD
1942 || e_action->index==ACTION_PASSWORD_WRITE)
1944 if (param->dtmf=='#') { /* current digit is '#' */
1945 if (e_state==EPOINT_STATE_IN_DISCONNECT
1946 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) { /* when disconnected, just #. when dialing, ##. */
1960 /* dialing using dtmf digit */
1961 if (e_state==EPOINT_STATE_IN_OVERLAP){ // && e_state==e_connectedmode)
1962 if (e_dialinginfo.id[0]=='\0' && !e_action) {
1963 set_tone(portlist, "dialing");
1965 /* concat dialing string */
1966 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id)) {
1967 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1968 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1974 /* port MESSAGE_CRYPT */
1975 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1978 /* send crypt response to cryptman */
1979 if (param->crypt.type == CR_MESSAGE_IND)
1980 cryptman_msg2man(param->crypt.data, param->crypt.len);
1982 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1986 /* port MESSAGE_OVERLAP */
1987 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1989 struct lcr_msg *message;
1991 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1993 /* signal to call tool */
1994 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1996 if (e_dialing_queue[0] && portlist) {
1997 /* send what we have not dialed yet, because we had no setup complete */
1998 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1999 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2000 SCPY(message->param.information.id, e_dialing_queue);
2001 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
2002 message_put(message);
2003 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
2004 e_dialing_queue[0] = '\0';
2006 /* check if pattern is available */
2007 if (!ea_endpoint->ep_portlist->next && portlist->early_b) { /* one port_list relation and tones available */
2008 /* indicate patterns */
2009 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2010 message_put(message);
2012 /* connect audio, if not already */
2013 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2014 message->param.audiopath = 1;
2015 message_put(message);
2017 /* indicate no patterns */
2018 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
2019 message_put(message);
2021 /* disconnect audio, if not already */
2022 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2023 message->param.audiopath = 0;
2024 message_put(message);
2026 new_state(EPOINT_STATE_OUT_OVERLAP);
2027 /* if we are in a join */
2028 if (ea_endpoint->ep_join_id) {
2029 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2030 memcpy(&message->param, param, sizeof(union parameter));
2031 message_put(message);
2035 /* port MESSAGE_PROCEEDING */
2036 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2038 struct lcr_msg *message;
2040 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2042 /* signal to call tool */
2043 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
2045 e_state = EPOINT_STATE_OUT_PROCEEDING;
2046 /* check if pattern is availatle */
2047 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
2048 /* indicate patterns */
2049 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2050 message_put(message);
2052 /* connect audio, if not already */
2053 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2054 message->param.audiopath = 1;
2055 message_put(message);
2057 /* indicate no patterns */
2058 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
2059 message_put(message);
2061 /* disconnect audio, if not already */
2062 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2063 message->param.audiopath = 0;
2064 message_put(message);
2066 /* if we are in a call */
2067 if (ea_endpoint->ep_join_id) {
2068 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2069 memcpy(&message->param, param, sizeof(union parameter));
2070 message_put(message);
2074 /* port MESSAGE_ALERTING */
2075 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
2077 struct lcr_msg *message;
2079 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2081 /* signal to call tool */
2082 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
2085 // set_tone(portlist, "hold");
2087 new_state(EPOINT_STATE_OUT_ALERTING);
2088 /* check if pattern is available */
2089 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) { /* one port_list relation and tones available */
2090 /* indicate patterns */
2091 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2092 message_put(message);
2094 /* connect audio, if not already */
2095 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2096 message->param.audiopath = 1;
2097 message_put(message);
2099 /* indicate no patterns */
2100 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
2101 message_put(message);
2103 /* disconnect audio, if not already */
2104 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2105 message->param.audiopath = 0;
2106 message_put(message);
2108 /* if we are in a call */
2109 if (ea_endpoint->ep_join_id) {
2110 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2111 memcpy(&message->param, param, sizeof(union parameter));
2112 message_put(message);
2116 /* port MESSAGE_CONNECT */
2117 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
2119 struct lcr_msg *message;
2121 unsigned int port_id = portlist->port_id;
2122 struct port_list *tportlist;
2126 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2128 /* signal to call tool */
2129 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype, options.national, options.international), 0, 0, 0);
2131 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
2132 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2133 while(ea_endpoint->ep_portlist->next) { /* as long as we have at least two ports */
2134 tportlist = ea_endpoint->ep_portlist;
2135 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2136 tportlist = tportlist->next;
2137 if (tportlist->port_id == port_id)
2138 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2139 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2140 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
2141 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2142 message_put(message);
2143 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
2144 ea_endpoint->free_portlist(tportlist);
2146 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2151 if (e_callerinfo.interface[0])
2152 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, e_connectinfo.interface);
2154 /* screen connected name */
2156 SCPY(e_connectinfo.name, e_ext.name);
2158 /* add internal id to colp */
2159 SCPY(e_connectinfo.extension, e_ext.number);
2161 /* we store the connected port number */
2162 SCPY(e_extension_interface, e_connectinfo.interface);
2164 /* for internal and am calls, we get the extension's id */
2165 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE) {
2166 SCPY(e_connectinfo.id, e_ext.callerid);
2167 SCPY(e_connectinfo.extension, e_ext.number);
2168 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2169 e_connectinfo.ntype = e_ext.callerid_type;
2170 e_connectinfo.present = e_ext.callerid_present;
2172 if (portlist->port_type==PORT_TYPE_VBOX_OUT) {
2173 e_connectinfo.itype = INFO_ITYPE_VBOX;
2174 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2177 new_state(EPOINT_STATE_CONNECT);
2179 /* set volume of rx and tx */
2180 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0) {
2181 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2182 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2183 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2184 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2185 message_put(message);
2188 unsched_timer(&e_cfnr_timeout);
2189 unsched_timer(&e_cfnr_call_timeout);
2190 if (e_ext.number[0])
2191 e_dtmf = 1; /* allow dtmf */
2194 /* other calls with no caller id (or not available for the extension) and force colp */
2195 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE) {
2196 e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
2197 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT) {
2198 /* external extension answered */
2199 port = find_port_id(portlist->port_id);
2201 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype, options.national, options.international));
2202 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2207 /* send connect to join */
2208 if (ea_endpoint->ep_join_id) {
2209 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2210 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2211 message_put(message);
2213 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2214 message->param.audiopath = 1;
2215 message_put(message);
2216 } else if (!e_adminid) {
2218 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2219 SCPY(e_ext.number, e_cbcaller);
2220 new_state(EPOINT_STATE_IN_OVERLAP);
2221 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2223 /* get extension's info about terminal */
2224 if (!read_extension(&e_ext, e_ext.number)) {
2225 /* extension doesn't exist */
2226 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2227 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2228 new_state(EPOINT_STATE_OUT_DISCONNECT);
2229 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2233 /* put prefix in front of e_cbdialing */
2234 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2235 SCPY(e_dialinginfo.id, buffer);
2236 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2237 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2239 /* use caller id (or if exist: id_next_call) for this call */
2240 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2241 SCPY(e_callerinfo.extension, e_ext.number);
2242 if (e_ext.id_next_call_present >= 0) {
2243 SCPY(e_callerinfo.id, e_ext.id_next_call);
2244 e_callerinfo.present = e_ext.id_next_call_present;
2245 e_callerinfo.ntype = e_ext.id_next_call_type;
2246 e_ext.id_next_call_present = -1;
2247 /* extension is written */
2248 write_extension(&e_ext, e_ext.number);
2250 SCPY(e_callerinfo.id, e_ext.callerid);
2251 e_callerinfo.present = e_ext.callerid_present;
2252 e_callerinfo.ntype = e_ext.callerid_type;
2254 e_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
2256 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2259 /* check if caller id is NOT authenticated */
2260 if (!parse_callbackauth(e_ext.number, &e_callbackinfo)) {
2261 /* make call state to enter password */
2262 new_state(EPOINT_STATE_IN_OVERLAP);
2263 e_action = &action_password_write;
2264 unsched_timer(&e_match_timeout);
2265 e_match_to_action = NULL;
2266 e_dialinginfo.id[0] = '\0';
2267 e_extdialing = strchr(e_dialinginfo.id, '\0');
2268 schedule_timer(&e_password_timeout, 20, 0);
2271 /* incoming call (callback) */
2272 e_ruleset = ruleset_main;
2274 e_rule = e_ruleset->rule_first;
2276 e_extdialing = e_dialinginfo.id;
2277 if (e_dialinginfo.id[0]) {
2278 set_tone(portlist, "dialing");
2281 set_tone(portlist, "dialpbx");
2284 } else { /* testcall */
2285 set_tone(portlist, "hold");
2288 /* start recording if enabled, not when answering machine answers */
2289 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)) {
2290 /* check if we are a terminal */
2291 if (e_ext.number[0] == '\0')
2292 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2294 port = find_port_id(portlist->port_id);
2296 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2301 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2302 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2304 struct lcr_msg *message;
2306 unsigned int port_id = portlist->port_id;
2310 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2312 /* signal to call tool */
2313 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2315 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2316 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE){ // || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2317 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2322 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);
2323 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2324 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2326 /* check if we have more than one portlist relation and we just ignore the disconnect */
2327 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next) {
2328 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2329 portlist = ea_endpoint->ep_portlist;
2331 if (portlist->port_id == port_id)
2333 portlist = portlist->next;
2336 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2337 if (message_type != MESSAGE_RELEASE) {
2338 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2339 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2340 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2341 message_put(message);
2342 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2344 ea_endpoint->free_portlist(portlist);
2345 return; /* one relation removed */
2347 if (e_state == EPOINT_STATE_CONNECT) {
2348 /* use cause from port after connect */
2349 cause = param->disconnectinfo.cause;
2350 location = param->disconnectinfo.location;
2352 /* use multipoint cause if no connect yet */
2353 if (e_multipoint_cause) {
2354 cause = e_multipoint_cause;
2355 location = e_multipoint_location;
2357 cause = CAUSE_NOUSER;
2358 location = LOCATION_PRIVATE_LOCAL;
2362 unsched_timer(&e_cfnr_timeout);
2363 unsched_timer(&e_cfnr_call_timeout);
2365 /* process hangup */
2366 process_hangup(e_join_cause, e_join_location);
2367 e_multipoint_cause = 0;
2368 e_multipoint_location = 0;
2370 if (message_type == MESSAGE_DISCONNECT) {
2371 /* tone to disconnected end */
2372 SPRINT(buffer, "cause_%02x", cause);
2373 if (ea_endpoint->ep_portlist)
2374 set_tone(ea_endpoint->ep_portlist, buffer);
2376 new_state(EPOINT_STATE_IN_DISCONNECT);
2379 if (ea_endpoint->ep_join_id) {
2380 int haspatterns = 0;
2381 /* check if pattern is available */
2382 if (ea_endpoint->ep_portlist)
2383 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2384 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
2385 && message_type != MESSAGE_RELEASE) // if we release, we are done
2388 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2389 /* indicate patterns */
2390 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2391 message_put(message);
2392 /* connect audio, if not already */
2393 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2394 message->param.audiopath = 1;
2395 message_put(message);
2396 /* send disconnect */
2397 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2398 memcpy(&message->param, param, sizeof(union parameter));
2399 message_put(message);
2400 /* disable encryption if disconnected */
2401 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2404 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2408 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2411 if (message_type == MESSAGE_RELEASE)
2412 ea_endpoint->free_portlist(portlist);
2413 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, callcause, portcause */
2414 return; /* must exit here */
2417 /* port MESSAGE_TIMEOUT */
2418 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2422 trace_header("TIMEOUT", DIRECTION_IN);
2423 message_type = MESSAGE_DISCONNECT;
2424 switch (param->state) {
2425 case PORT_STATE_OUT_SETUP:
2426 case PORT_STATE_OUT_OVERLAP:
2427 add_trace("state", NULL, "outgoing setup/dialing");
2429 /* no user responding */
2430 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2431 return; /* must exit here */
2433 case PORT_STATE_IN_SETUP:
2434 case PORT_STATE_IN_OVERLAP:
2435 add_trace("state", NULL, "incoming setup/dialing");
2436 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2437 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2440 case PORT_STATE_OUT_PROCEEDING:
2441 add_trace("state", NULL, "outgoing proceeding");
2443 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2444 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2445 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2446 return; /* must exit here */
2448 case PORT_STATE_IN_PROCEEDING:
2449 add_trace("state", NULL, "incoming proceeding");
2450 param->disconnectinfo.cause = CAUSE_NOUSER;
2451 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2454 case PORT_STATE_OUT_ALERTING:
2455 add_trace("state", NULL, "outgoing alerting");
2457 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2458 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2459 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2460 return; /* must exit here */
2462 case PORT_STATE_CONNECT:
2463 add_trace("state", NULL, "connect");
2465 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2466 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2467 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2468 return; /* must exit here */
2470 case PORT_STATE_IN_ALERTING:
2471 add_trace("state", NULL, "incoming alerting");
2472 param->disconnectinfo.cause = CAUSE_NOANSWER;
2473 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2476 case PORT_STATE_IN_DISCONNECT:
2477 case PORT_STATE_OUT_DISCONNECT:
2478 add_trace("state", NULL, "disconnect");
2480 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2481 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0);
2482 return; /* must exit here */
2485 param->disconnectinfo.cause = 31; /* normal unspecified */
2486 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2489 /* release call, disconnect isdn */
2491 new_state(EPOINT_STATE_OUT_DISCONNECT);
2492 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2493 SCPY(e_tone, cause);
2495 set_tone(portlist, cause);
2496 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2497 portlist = portlist->next;
2499 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
2502 /* port MESSAGE_NOTIFY */
2503 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2505 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2507 struct lcr_msg *message;
2508 const char *logtext = "";
2511 /* signal to call tool */
2512 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);
2513 if (param->notifyinfo.notify) {
2514 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2517 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2518 if (param->notifyinfo.local) switch(param->notifyinfo.notify) {
2519 case INFO_NOTIFY_REMOTE_HOLD:
2520 case INFO_NOTIFY_USER_SUSPENDED:
2521 /* tell call about it */
2522 if (ea_endpoint->ep_join_id) {
2523 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2524 message->param.audiopath = 0;
2525 message_put(message);
2529 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2530 case INFO_NOTIFY_USER_RESUMED:
2531 /* set volume of rx and tx */
2532 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2533 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2535 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2536 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2537 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2538 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2539 message_put(message);
2541 /* set current tone */
2543 set_tone(portlist, e_tone);
2544 /* tell call about it */
2545 if (ea_endpoint->ep_join_id) {
2546 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2547 message->param.audiopath = 1;
2548 message_put(message);
2553 /* get name of notify */
2554 switch(param->notifyinfo.notify) {
2559 logtext = "USER_SUSPENDED";
2562 logtext = "BEARER_SERVICE_CHANGED";
2565 logtext = "USER_RESUMED";
2568 logtext = "CONFERENCE_ESTABLISHED";
2571 logtext = "CONFERENCE_DISCONNECTED";
2574 logtext = "OTHER_PARTY_ADDED";
2577 logtext = "ISOLATED";
2580 logtext = "REATTACHED";
2583 logtext = "OTHER_PARTY_ISOLATED";
2586 logtext = "OTHER_PARTY_REATTACHED";
2589 logtext = "OTHER_PARTY_SPLIT";
2592 logtext = "OTHER_PARTY_DISCONNECTED";
2595 logtext = "CONFERENCE_FLOATING";
2598 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2601 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2604 logtext = "CALL_IS_A_WAITING_CALL";
2607 logtext = "DIVERSION_ACTIVATED";
2610 logtext = "RESERVED_CT_1";
2613 logtext = "RESERVED_CT_2";
2616 logtext = "REVERSE_CHARGING";
2619 logtext = "REMOTE_HOLD";
2622 logtext = "REMOTE_RETRIEVAL";
2625 logtext = "CALL_IS_DIVERTING";
2628 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2633 /* notify call if available */
2634 if (ea_endpoint->ep_join_id) {
2635 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2636 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2637 message_put(message);
2642 /* port MESSAGE_PROGRESS */
2643 void EndpointAppPBX::port_progress(struct port_list *portlist, int message_type, union parameter *param)
2645 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2647 struct lcr_msg *message;
2649 /* signal to call tool */
2650 admin_call_response(e_adminid, ADMIN_CALL_PROGRESS, "", 0, param->progressinfo.location, param->progressinfo.progress);
2652 /* send progress to call if available */
2653 if (ea_endpoint->ep_join_id) {
2654 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PROGRESS);
2655 memcpy(&message->param.progressinfo, ¶m->progressinfo, sizeof(struct progress_info));
2656 message_put(message);
2661 /* port MESSAGE_FACILITY */
2662 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2664 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2666 struct lcr_msg *message;
2668 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2669 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2670 message_put(message);
2673 /* port MESSAGE_SUSPEND */
2674 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2675 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2677 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2679 /* epoint is now parked */
2680 ea_endpoint->ep_park = 1;
2681 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2682 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2684 /* remove port relation */
2685 ea_endpoint->free_portlist(portlist);
2688 /* port MESSAGE_RESUME */
2689 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2690 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2692 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2694 /* epoint is now resumed */
2695 ea_endpoint->ep_park = 0;
2699 /* port MESSAGE_ENABLEKEYPAD */
2700 void EndpointAppPBX::port_enablekeypad(struct port_list *portlist, int message_type, union parameter *param)
2702 struct lcr_msg *message;
2704 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2706 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_ENABLEKEYPAD);
2707 memcpy(&message->param, param, sizeof(union parameter));
2708 message_put(message);
2712 /* port sends message to the endpoint
2714 void EndpointAppPBX::ea_message_port(unsigned int port_id, int message_type, union parameter *param)
2716 struct port_list *portlist;
2718 portlist = ea_endpoint->ep_portlist;
2720 if (port_id == portlist->port_id)
2722 portlist = portlist->next;
2725 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);
2729 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2730 switch(message_type) {
2731 case MESSAGE_TONE_EOF: /* tone is end of file */
2732 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2734 if (e_action->index == ACTION_VBOX_PLAY) {
2737 if (e_action->index == ACTION_EFI) {
2743 case MESSAGE_TONE_COUNTER: /* counter info received */
2744 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);
2746 if (e_action->index == ACTION_VBOX_PLAY) {
2747 e_vbox_counter = param->counter.current;
2748 if (param->counter.max >= 0)
2749 e_vbox_counter_max = param->counter.max;
2753 /* PORT sends SETUP message */
2755 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);
2756 if (e_state!=EPOINT_STATE_IDLE) {
2757 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2760 port_setup(portlist, message_type, param);
2763 /* PORT sends INFORMATION message */
2764 case MESSAGE_INFORMATION: /* additional digits received */
2765 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);
2766 port_information(portlist, message_type, param);
2769 /* PORT sends FACILITY message */
2770 case MESSAGE_FACILITY:
2771 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2772 port_facility(portlist, message_type, param);
2775 /* PORT sends DTMF message */
2776 case MESSAGE_DTMF: /* dtmf digits received */
2777 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);
2778 port_dtmf(portlist, message_type, param);
2781 /* PORT sends CRYPT message */
2782 case MESSAGE_CRYPT: /* crypt response received */
2783 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2784 port_crypt(portlist, message_type, param);
2787 /* PORT sends MORE message */
2788 case MESSAGE_OVERLAP:
2789 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);
2790 if (e_state != EPOINT_STATE_OUT_SETUP) {
2791 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);
2794 port_overlap(portlist, message_type, param);
2797 /* PORT sends PROCEEDING message */
2798 case MESSAGE_PROCEEDING: /* port is proceeding */
2799 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);
2800 if (e_state!=EPOINT_STATE_OUT_SETUP
2801 && e_state!=EPOINT_STATE_OUT_OVERLAP) {
2802 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);
2805 port_proceeding(portlist, message_type, param);
2808 /* PORT sends ALERTING message */
2809 case MESSAGE_ALERTING:
2810 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);
2811 if (e_state!=EPOINT_STATE_OUT_SETUP
2812 && e_state!=EPOINT_STATE_OUT_OVERLAP
2813 && e_state!=EPOINT_STATE_OUT_PROCEEDING) {
2814 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);
2817 port_alerting(portlist, message_type, param);
2820 /* PORT sends CONNECT message */
2821 case MESSAGE_CONNECT:
2822 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);
2823 if (e_state!=EPOINT_STATE_OUT_SETUP
2824 && e_state!=EPOINT_STATE_OUT_OVERLAP
2825 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2826 && e_state!=EPOINT_STATE_OUT_ALERTING) {
2827 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2830 port_connect(portlist, message_type, param);
2833 /* PORT sends DISCONNECT message */
2834 case MESSAGE_DISCONNECT: /* port is disconnected */
2835 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);
2836 port_disconnect_release(portlist, message_type, param);
2839 /* PORT sends a RELEASE message */
2840 case MESSAGE_RELEASE: /* port releases */
2841 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);
2842 /* portlist is release at port_disconnect_release, thanx Paul */
2843 port_disconnect_release(portlist, message_type, param);
2846 /* PORT sends a TIMEOUT message */
2847 case MESSAGE_TIMEOUT:
2848 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);
2849 port_timeout(portlist, message_type, param);
2850 break; /* release */
2852 /* PORT sends a NOTIFY message */
2853 case MESSAGE_NOTIFY:
2854 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);
2855 port_notify(portlist, message_type, param);
2858 /* PORT sends a PROGRESS message */
2859 case MESSAGE_PROGRESS:
2860 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);
2861 port_progress(portlist, message_type, param);
2864 /* PORT sends a SUSPEND message */
2865 case MESSAGE_SUSPEND:
2866 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);
2867 port_suspend(portlist, message_type, param);
2868 break; /* suspend */
2870 /* PORT sends a RESUME message */
2871 case MESSAGE_RESUME:
2872 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);
2873 port_resume(portlist, message_type, param);
2877 kann nach dem test gelöscht werden, da eine direkte funktion im join und im mISDN zum austausch der message existiert
2878 /* port assigns bchannel */
2879 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2880 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);
2881 /* only one port is expected to be connected to bchannel */
2882 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2883 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2887 /* PORT requests DTMF */
2888 case MESSAGE_ENABLEKEYPAD:
2889 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);
2890 port_enablekeypad(portlist, message_type, param);
2895 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);
2898 /* Note: this endpoint may be destroyed, so we MUST return */
2902 /* messages from join
2904 /* join MESSAGE_CRYPT */
2905 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2908 switch(param->crypt.type) {
2909 /* message from remote port to "crypt manager" */
2910 case CU_ACTK_REQ: /* activate key-exchange */
2911 case CU_ACTS_REQ: /* activate shared key */
2912 case CU_DACT_REQ: /* deactivate */
2913 case CU_INFO_REQ: /* request last info message */
2914 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2917 /* message from "crypt manager" to user */
2918 case CU_ACTK_CONF: /* key-echange done */
2919 case CU_ACTS_CONF: /* shared key done */
2920 case CU_DACT_CONF: /* deactivated */
2921 case CU_DACT_IND: /* deactivated */
2922 case CU_ERROR_IND: /* receive error message */
2923 case CU_INFO_IND: /* receive info message */
2924 case CU_INFO_CONF: /* receive info message */
2925 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2929 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);
2934 /* join MESSAGE_INFORMATION */
2935 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2937 struct lcr_msg *message;
2942 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2943 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2944 message_put(message);
2945 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2946 portlist = portlist->next;
2950 /* join MESSAGE_FACILITY */
2951 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2953 struct lcr_msg *message;
2955 if (!e_ext.facility && e_ext.number[0]) {
2960 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2961 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2962 message_put(message);
2963 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2964 portlist = portlist->next;
2968 /* join MESSAGE_MORE */
2969 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2971 struct lcr_msg *message;
2973 new_state(EPOINT_STATE_IN_OVERLAP);
2976 if (e_join_pattern && e_ext.own_setup) {
2977 /* disconnect audio */
2978 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2979 message->param.audiopath = 0;
2980 message_put(message);
2982 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
2983 if (e_dialinginfo.id[0])
2984 set_tone(portlist, "dialing");
2986 set_tone(portlist, "dialtone");
2989 if (e_dialinginfo.id[0]) {
2990 set_tone(portlist, "dialing");
2992 if (e_ext.number[0])
2993 set_tone(portlist, "dialpbx");
2995 set_tone(portlist, "dialtone");
2999 /* join MESSAGE_PROCEEDING */
3000 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
3002 struct lcr_msg *message;
3004 new_state(EPOINT_STATE_IN_PROCEEDING);
3006 /* own proceeding tone */
3007 if (e_join_pattern) {
3008 /* connect / disconnect audio */
3009 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3010 if (e_ext.own_proceeding)
3011 message->param.audiopath = 0;
3013 message->param.audiopath = 1;
3014 message_put(message);
3016 // UCPY(e_join_tone, "proceeding");
3018 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3019 message_put(message);
3020 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3022 set_tone(portlist, "proceeding");
3025 /* join MESSAGE_ALERTING */
3026 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
3028 struct lcr_msg *message;
3030 new_state(EPOINT_STATE_IN_ALERTING);
3032 /* own alerting tone */
3033 if (e_join_pattern) {
3034 /* connect / disconnect audio */
3035 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3036 if (e_ext.own_alerting)
3037 message->param.audiopath = 0;
3039 message->param.audiopath = 1;
3040 message_put(message);
3043 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
3044 message_put(message);
3045 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3047 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL) {
3048 set_tone(portlist, "ringing");
3051 if (e_ext.number[0])
3052 set_tone(portlist, "ringpbx");
3054 set_tone(portlist, "ringing");
3056 if (e_ext.number[0])
3057 e_dtmf = 1; /* allow dtmf */
3060 /* join MESSAGE_CONNECT */
3061 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
3063 struct lcr_msg *message;
3066 new_state(EPOINT_STATE_CONNECT);
3067 // UCPY(e_join_tone, "");
3069 if (e_ext.number[0])
3070 e_dtmf = 1; /* allow dtmf */
3073 unsched_timer(&e_powerdial_timeout);
3074 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
3076 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3077 memcpy(&message->param, param, sizeof(union parameter));
3079 /* screen clip if prefix is required */
3080 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0]) {
3081 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
3082 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype, options.national, options.international));
3083 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3086 /* use internal caller id */
3087 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore)) {
3088 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
3089 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3092 /* handle restricted caller ids */
3093 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);
3094 /* display callerid if desired for extension */
3095 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));
3097 /* use conp, if enabld */
3098 // if (!e_ext.centrex)
3099 // message->param.connectinfo.name[0] = '\0';
3102 message_put(message);
3103 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3105 set_tone(portlist, NULL);
3107 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3108 message->param.audiopath = 1;
3109 message_put(message);
3114 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3115 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3118 struct lcr_msg *message;
3119 struct port_list *portlist = NULL;
3123 /* be sure that we are active */
3125 e_tx_state = NOTIFY_STATE_ACTIVE;
3127 /* we are powerdialing, if e_powerdial_on is set and limit is not exceeded if given */
3128 if (e_powerdial_on && ((e_powercount+1)<e_powerlimit || e_powerlimit<1)) {
3129 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL,0 ); /* RELEASE_TYPE, join, port */
3131 /* set time for power dialing */
3132 schedule_timer(&e_powerdial_timeout, (int)e_powerdelay, 0); /* set redial in the future */
3135 /* set redial tone */
3136 if (ea_endpoint->ep_portlist) {
3139 set_tone(ea_endpoint->ep_portlist, "redial");
3140 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);
3141 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3142 if (e_state==EPOINT_STATE_IN_OVERLAP) {
3143 new_state(EPOINT_STATE_IN_PROCEEDING);
3144 if (ea_endpoint->ep_portlist) {
3145 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3146 message_put(message);
3147 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3149 /* caused the error, that the first knock sound was not there */
3150 /* set_tone(portlist, "proceeding"); */
3152 /* send display of powerdialing */
3153 if (e_ext.display_dialing) {
3154 portlist = ea_endpoint->ep_portlist;
3156 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3158 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3160 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3161 message_put(message);
3162 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3163 portlist = portlist->next;
3173 if ((e_state!=EPOINT_STATE_CONNECT
3174 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3175 && e_state!=EPOINT_STATE_IN_OVERLAP
3176 && e_state!=EPOINT_STATE_IN_PROCEEDING
3177 && e_state!=EPOINT_STATE_IN_ALERTING)
3178 || !ea_endpoint->ep_portlist) { /* or no port */
3179 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3180 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause, 0); /* RELEASE_TYPE, join, port */
3181 return; /* must exit here */
3184 if (!e_join_cause) {
3185 e_join_cause = param->disconnectinfo.cause;
3186 e_join_location = param->disconnectinfo.location;
3189 /* on release we need the audio again! */
3190 if (message_type == MESSAGE_RELEASE) {
3192 ea_endpoint->ep_join_id = 0;
3194 /* disconnect and select tone */
3195 new_state(EPOINT_STATE_OUT_DISCONNECT);
3196 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3197 /* if own_cause, we must release the join */
3198 if (e_ext.own_cause /* own cause */
3199 || !e_join_pattern) { /* no patterns */
3200 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);
3201 if (message_type != MESSAGE_RELEASE)
3202 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, 0); /* RELEASE_TYPE, join, port */
3204 } else { /* else we enable audio */
3205 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3206 message->param.audiopath = 1;
3207 message_put(message);
3209 /* send disconnect message */
3210 SCPY(e_tone, cause);
3211 portlist = ea_endpoint->ep_portlist;
3213 set_tone(portlist, cause);
3214 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3215 portlist = portlist->next;
3219 /* join MESSAGE_SETUP */
3220 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3222 struct lcr_msg *message;
3223 // struct interface *interface;
3225 /* if we already in setup state, we just update the dialing with new digits */
3226 if (e_state == EPOINT_STATE_OUT_SETUP
3227 || e_state == EPOINT_STATE_OUT_OVERLAP) {
3228 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3229 /* if digits changed, what we have already dialed */
3230 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id))) {
3231 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);
3232 /* release all ports */
3233 while((portlist = ea_endpoint->ep_portlist)) {
3234 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3235 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3236 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3237 message_put(message);
3238 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3239 ea_endpoint->free_portlist(portlist);
3242 /* disconnect audio */
3243 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3244 message->param.audiopath = 0;
3245 message_put(message);
3247 /* get dialing info */
3248 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3249 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3250 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3251 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3252 new_state(EPOINT_STATE_OUT_OVERLAP);
3255 schedule_timer(&e_redial_timeout, 1, 0);
3258 /* if we have a pending redial, so we just adjust the dialing number */
3259 if (e_redial_timeout.active) {
3260 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);
3261 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3264 if (!ea_endpoint->ep_portlist) {
3265 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3267 if (ea_endpoint->ep_portlist->next) {
3268 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3270 if (e_state == EPOINT_STATE_OUT_SETUP) {
3272 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);
3273 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3276 /* get what we have not dialed yet */
3277 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));
3278 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3279 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3280 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3281 message_put(message);
3282 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3284 /* always store what we have dialed or queued */
3285 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3289 if (e_state != EPOINT_STATE_IDLE) {
3290 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3293 /* if an internal extension is dialed, copy that number */
3294 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3295 SCPY(e_ext.number, param->setup.dialinginfo.id);
3296 /* if an internal extension is dialed, get extension's info about caller */
3297 if (e_ext.number[0]) {
3298 if (!read_extension(&e_ext, e_ext.number)) {
3299 e_ext.number[0] = '\0';
3300 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3304 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3305 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3306 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3307 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3308 memcpy(&e_rtpinfo, ¶m->setup.rtpinfo, sizeof(e_rtpinfo));
3310 /* process (voice over) data calls */
3311 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO) {
3312 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3313 memset(&e_capainfo, 0, sizeof(e_capainfo));
3314 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3315 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3316 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3319 new_state(EPOINT_STATE_OUT_SETUP);
3320 /* call special setup routine */
3324 /* join MESSAGE_mISDNSIGNAL */
3325 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3327 struct lcr_msg *message;
3330 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3331 memcpy(&message->param, param, sizeof(union parameter));
3332 message_put(message);
3333 portlist = portlist->next;
3337 /* join MESSAGE_BRIDE */
3338 void EndpointAppPBX::join_bridge(struct port_list *portlist, int message_type, union parameter *param)
3340 struct lcr_msg *message;
3343 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_BRIDGE);
3344 memcpy(&message->param, param, sizeof(union parameter));
3345 message_put(message);
3346 portlist = portlist->next;
3350 /* join MESSAGE_NOTIFY */
3351 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3353 struct lcr_msg *message;
3356 if (param->notifyinfo.notify) {
3357 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3358 // /* if notification was generated locally, we turn hold music on/off */
3359 // if (param->notifyinfo.local)
3360 // 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)
3364 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND) {
3365 if (!strcmp(e_tone, "hold")) { // don't interrupt other tones
3367 set_tone(portlist, "");
3368 portlist = portlist->next;
3371 portlist = ea_endpoint->ep_portlist;
3376 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND) {
3378 set_tone(portlist, "hold");
3379 portlist = portlist->next;
3381 portlist = ea_endpoint->ep_portlist;
3386 /* save new state */
3387 e_tx_state = new_state;
3390 /* notify port(s) about it */
3392 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3393 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3394 /* handle restricted caller ids */
3395 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3396 /* display callerid if desired for extension */
3397 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));
3398 message_put(message);
3399 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3400 portlist = portlist->next;
3404 /* join MESSAGE_DTMF */
3405 void EndpointAppPBX::join_dtmf(struct port_list *portlist, int message_type, union parameter *param)
3407 struct lcr_msg *message;
3410 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DTMF);
3411 memcpy(&message->param, param, sizeof(union parameter));
3412 message_put(message);
3413 portlist = portlist->next;
3417 /* JOIN sends messages to the endpoint
3419 void EndpointAppPBX::ea_message_join(unsigned int join_id, int message_type, union parameter *param)
3421 struct port_list *portlist;
3422 struct lcr_msg *message;
3425 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3429 portlist = ea_endpoint->ep_portlist;
3431 // 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);
3432 switch(message_type) {
3433 /* JOIN SENDS TONE message */
3435 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);
3436 set_tone(portlist, param->tone.name);
3439 /* JOIN SENDS CRYPT message */
3441 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);
3442 join_crypt(portlist, message_type, param);
3445 /* JOIN sends INFORMATION message */
3446 case MESSAGE_INFORMATION:
3447 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);
3448 join_information(portlist, message_type, param);
3451 /* JOIN sends FACILITY message */
3452 case MESSAGE_FACILITY:
3453 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);
3454 join_facility(portlist, message_type, param);
3457 /* JOIN sends OVERLAP message */
3458 case MESSAGE_OVERLAP:
3459 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);
3460 if (e_state!=EPOINT_STATE_IN_SETUP
3461 && e_state!=EPOINT_STATE_IN_OVERLAP) {
3462 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3465 join_overlap(portlist, message_type, param);
3468 /* JOIN sends PROCEEDING message */
3469 case MESSAGE_PROCEEDING:
3470 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);
3471 if(e_state!=EPOINT_STATE_IN_OVERLAP) {
3472 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3475 join_proceeding(portlist, message_type, param);
3478 /* JOIN sends ALERTING message */
3479 case MESSAGE_ALERTING:
3480 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);
3481 if (e_state!=EPOINT_STATE_IN_OVERLAP
3482 && e_state!=EPOINT_STATE_IN_PROCEEDING) {
3483 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3486 join_alerting(portlist, message_type, param);
3489 /* JOIN sends CONNECT message */
3490 case MESSAGE_CONNECT:
3491 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);
3492 if (e_state!=EPOINT_STATE_IN_OVERLAP
3493 && e_state!=EPOINT_STATE_IN_PROCEEDING
3494 && e_state!=EPOINT_STATE_IN_ALERTING) {
3495 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3498 join_connect(portlist, message_type, param);
3501 /* JOIN sends DISCONNECT/RELEASE message */
3502 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3503 case MESSAGE_RELEASE: /* JOIN releases */
3504 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);
3505 join_disconnect_release(message_type, param);
3508 /* JOIN sends SETUP message */
3510 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);
3511 join_setup(portlist, message_type, param);
3514 /* JOIN sends special mISDNSIGNAL message */
3515 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3516 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);
3517 join_mISDNsignal(portlist, message_type, param);
3520 /* JOIN sends bridge message */
3521 case MESSAGE_BRIDGE: /* bride message to port */
3522 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);
3523 join_bridge(portlist, message_type, param);
3526 /* JOIN has pattern available */
3527 case MESSAGE_PATTERN: /* indicating pattern available */
3528 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);
3529 if (!e_join_pattern) {
3530 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3534 set_tone(portlist, NULL);
3535 portlist = portlist->next;
3537 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3538 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3539 message->param.audiopath = 1;
3540 message_put(message);
3544 /* JOIN has no pattern available */
3545 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3546 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);
3547 if (e_join_pattern) {
3548 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3550 /* disconnect our audio tx and rx */
3551 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3552 message->param.audiopath = 0;
3553 message_put(message);
3558 /* JOIN (dunno at the moment) */
3559 case MESSAGE_REMOTE_AUDIO:
3560 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);
3561 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3562 message->param.audiopath = param->channel;
3563 message_put(message);
3567 /* JOIN sends a notify message */
3568 case MESSAGE_NOTIFY:
3569 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);
3570 join_notify(portlist, message_type, param);
3573 /* JOIN wants keypad / dtmf */
3574 case MESSAGE_ENABLEKEYPAD:
3575 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);
3578 trace_header("ENABLE KEYPAD", DIRECTION_NONE);
3582 /* JOIN sends a DTMF message */
3584 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);
3585 join_dtmf(portlist, message_type, param);
3589 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);
3594 /* pick_join will connect the first incoming call found. the endpoint
3595 * will receivce a MESSAGE_CONNECT.
3597 int match_list(char *list, char *item)
3599 char *end, *next = NULL;
3601 /* no list make matching */
3606 /* eliminate white spaces */
3607 while (*list > '\0' && *list <= ' ')
3613 /* if end of list is reached, we return */
3614 if (list[0] == '\0')
3616 /* if we have more than one entry (left) */
3617 if ((end = strchr(list, ',')))
3620 next = end = strchr(list, '\0');
3621 while (*(end-1) <= ' ')
3623 /* if string part matches item */
3624 if (!strncmp(list, item, end-list))
3630 void EndpointAppPBX::pick_join(char *extensions)
3632 struct lcr_msg *message;
3633 struct port_list *portlist;
3635 class EndpointAppPBX *eapp, *found;
3637 class JoinPBX *joinpbx;
3638 struct join_relation *relation;
3641 /* find an endpoint that is ringing internally or vbox with higher priority */
3644 eapp = apppbx_first;
3646 if (eapp!=this && ea_endpoint->ep_portlist) {
3647 portlist = eapp->ea_endpoint->ep_portlist;
3649 if ((port = find_port_id(portlist->port_id))) {
3650 if (port->p_type == PORT_TYPE_VBOX_OUT) {
3651 if (match_list(extensions, eapp->e_ext.number)) {
3657 if ((portlist->port_type & PORT_CLASS_DIR_MASK) == PORT_CLASS_DIR_OUT
3658 && port->p_state==PORT_STATE_OUT_ALERTING)
3659 if (match_list(extensions, eapp->e_ext.number)) {
3663 portlist = portlist->next;
3671 /* if no endpoint found */
3673 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);
3675 set_tone(ea_endpoint->ep_portlist, "cause_10");
3676 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3677 new_state(EPOINT_STATE_OUT_DISCONNECT);
3682 if (ea_endpoint->ep_join_id) {
3683 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3686 if (!eapp->ea_endpoint->ep_join_id) {
3687 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3690 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3692 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3695 if (join->j_type != JOIN_TYPE_PBX) {
3696 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3699 joinpbx = (class JoinPBX *)join;
3700 relation = joinpbx->j_relation;
3702 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3705 while (relation->epoint_id != eapp->ea_endpoint->ep_serial) {
3706 relation = relation->next;
3708 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3713 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3715 if (options.deb & DEBUG_EPOINT) {
3716 class Join *debug_c = join_first;
3717 class Endpoint *debug_e = epoint_first;
3718 class Port *debug_p = port_first;
3720 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3722 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3724 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3725 debug_c = debug_c->next;
3727 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3729 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3730 debug_e = debug_e->next;
3732 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3734 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3735 debug_p = debug_p->next;
3740 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3741 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3742 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3744 /* connnecting our endpoint */
3745 new_state(EPOINT_STATE_CONNECT);
3746 if (e_ext.number[0])
3748 set_tone(ea_endpoint->ep_portlist, NULL);
3750 /* now we send a release to the ringing endpoint */
3751 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3752 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3753 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3754 message_put(message);
3756 /* we send a connect to the join with our caller id */
3757 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3758 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3759 message->param.connectinfo.present = e_callerinfo.present;
3760 message->param.connectinfo.screen = e_callerinfo.screen;
3761 message->param.connectinfo.itype = e_callerinfo.itype;
3762 message->param.connectinfo.ntype = e_callerinfo.ntype;
3763 message_put(message);
3765 /* we send a connect to our port with the remote callerid */
3766 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3767 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3768 message->param.connectinfo.present = eapp->e_callerinfo.present;
3769 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3770 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3771 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3772 /* handle restricted caller ids */
3773 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);
3774 /* display callerid if desired for extension */
3775 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));
3776 message_put(message);
3778 /* we send a connect to the audio path (not for vbox) */
3779 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3780 message->param.audiopath = 1;
3781 message_put(message);
3783 /* beeing paranoid, we make call update */
3784 trigger_work(&joinpbx->j_updatebridge);
3786 if (options.deb & DEBUG_EPOINT) {
3787 class Join *debug_c = join_first;
3788 class Endpoint *debug_e = epoint_first;
3789 class Port *debug_p = port_first;
3791 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3793 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3795 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3796 debug_c = debug_c->next;
3798 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3800 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3801 debug_e = debug_e->next;
3803 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3805 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3806 debug_p = debug_p->next;
3812 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3814 void EndpointAppPBX::join_join(void)
3817 struct lcr_msg *message;
3818 struct join_relation *our_relation, *other_relation;
3819 struct join_relation **our_relation_pointer, **other_relation_pointer;
3820 class Join *our_join, *other_join;
3821 class JoinPBX *our_joinpbx, *other_joinpbx;
3822 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3823 class Port *our_port, *other_port;
3824 class Pdss1 *our_pdss1, *other_pdss1;
3826 /* are we a candidate to join a join? */
3827 our_join = find_join_id(ea_endpoint->ep_join_id);
3829 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3832 if (our_join->j_type != JOIN_TYPE_PBX) {
3833 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3836 our_joinpbx = (class JoinPBX *)our_join;
3837 if (!ea_endpoint->ep_portlist) {
3838 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3841 if (!e_ext.number[0]) {
3842 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3845 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3847 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3850 if ((our_port->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) {
3851 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3854 our_pdss1 = (class Pdss1 *)our_port;
3856 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3857 other_eapp = apppbx_first;
3859 if (other_eapp == this) {
3860 other_eapp = other_eapp->next;
3863 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);
3864 if (other_eapp->e_ext.number[0] /* has terminal */
3865 && other_eapp->ea_endpoint->ep_portlist /* has port */
3866 && other_eapp->ea_endpoint->ep_join_id) { /* has join */
3867 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3868 if (other_port) { /* port still exists */
3869 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3870 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) { /* port is isdn nt-mode */
3871 other_pdss1 = (class Pdss1 *)other_port;
3872 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);
3873 if (other_pdss1->p_m_hold /* port is on hold */
3874 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3875 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3878 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3881 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3884 other_eapp = other_eapp->next;
3887 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn terminal.\n", ea_endpoint->ep_serial);
3890 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port with same terminal found.\n", ea_endpoint->ep_serial);
3892 /* if we have the same join */
3893 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id) {
3894 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we and the other have the same join.\n", ea_endpoint->ep_serial);
3897 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3899 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3902 if (other_join->j_type != JOIN_TYPE_PBX) {
3903 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3906 other_joinpbx = (class JoinPBX *)other_join;
3907 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline) {
3908 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3912 /* remove relation to endpoint for join on hold */
3913 other_relation = other_joinpbx->j_relation;
3914 other_relation_pointer = &other_joinpbx->j_relation;
3915 while(other_relation) {
3916 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial) {
3917 /* detach other endpoint on hold */
3918 *other_relation_pointer = other_relation->next;
3919 FREE(other_relation, sizeof(struct join_relation));
3921 other_relation = *other_relation_pointer;
3922 other_eapp->ea_endpoint->ep_join_id = 0;
3926 /* change join/hold pointer of endpoint to the new join */
3927 temp_epoint = find_epoint_id(other_relation->epoint_id);
3929 if (temp_epoint->ep_join_id == other_join->j_serial)
3930 temp_epoint->ep_join_id = our_join->j_serial;
3933 other_relation_pointer = &other_relation->next;
3934 other_relation = other_relation->next;
3936 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3938 /* join call relations */
3939 our_relation = our_joinpbx->j_relation;
3940 our_relation_pointer = &our_joinpbx->j_relation;
3941 while(our_relation) {
3942 our_relation_pointer = &our_relation->next;
3943 our_relation = our_relation->next;
3945 *our_relation_pointer = other_joinpbx->j_relation;
3946 other_joinpbx->j_relation = NULL;
3947 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3949 /* release endpoint on hold */
3950 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3951 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3952 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3953 message_put(message);
3955 /* if we are not a partyline, we get partyline state from other join */
3956 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3958 /* remove empty join */
3960 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3962 /* mixer must update */
3963 trigger_work(&our_joinpbx->j_updatebridge);
3965 /* we send a retrieve to that endpoint */
3966 // mixer will update the hold-state of the join and send it to the endpoints is changes
3968 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no mISDN support anyway.\n", ea_endpoint->ep_serial);
3973 /* check if we have an external call
3974 * this is used to check for encryption ability
3976 int EndpointAppPBX::check_external(const char **errstr, class Port **port)
3978 struct join_relation *relation;
3980 class JoinPBX *joinpbx;
3981 class Endpoint *epoint;
3983 /* some paranoia check */
3984 if (!ea_endpoint->ep_portlist) {
3985 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3986 *errstr = "No Call";
3989 if (!e_ext.number[0]) {
3990 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3991 *errstr = "No Call";
3995 /* check if we have a join with 2 parties */
3996 join = find_join_id(ea_endpoint->ep_join_id);
3998 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3999 *errstr = "No Call";
4002 if (join->j_type != JOIN_TYPE_PBX) {
4003 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
4004 *errstr = "No PBX Call";
4007 joinpbx = (class JoinPBX *)join;
4008 relation = joinpbx->j_relation;
4010 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
4011 *errstr = "No Call";
4014 if (!relation->next) {
4015 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
4016 *errstr = "No Call";
4019 if (relation->next->next) {
4020 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
4021 *errstr = "Err: Conference";
4024 if (relation->epoint_id == ea_endpoint->ep_serial) {
4025 relation = relation->next;
4026 if (relation->epoint_id == ea_endpoint->ep_serial) {
4027 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4028 *errstr = "Software Error";
4033 /* check remote port for external call */
4034 epoint = find_epoint_id(relation->epoint_id);
4036 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4037 *errstr = "No Call";
4040 if (!epoint->ep_portlist) {
4041 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4042 *errstr = "No Call";
4045 *port = find_port_id(epoint->ep_portlist->port_id);
4047 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4048 *errstr = "No Call";
4051 if (((*port)->p_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_DSS1) { /* port is not external isdn */
4052 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4053 *errstr = "No Ext Call";
4056 if ((*port)->p_state != PORT_STATE_CONNECT) {
4057 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4058 *errstr = "No Ext Connect";
4064 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned int port_id, int dir)
4066 const char *logtext = "unknown";
4069 switch(message_type) {
4071 trace_header("SETUP", dir);
4072 if (dir == DIRECTION_OUT)
4073 add_trace("to", NULL, "CH(%lu)", port_id);
4074 if (dir == DIRECTION_IN)
4075 add_trace("from", NULL, "CH(%lu)", port_id);
4076 if (param->setup.callerinfo.extension[0])
4077 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4078 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype, options.national, options.international));
4079 switch(param->setup.callerinfo.present) {
4080 case INFO_PRESENT_RESTRICTED:
4081 add_trace("caller id", "present", "restricted");
4083 case INFO_PRESENT_ALLOWED:
4084 add_trace("caller id", "present", "allowed");
4087 add_trace("caller id", "present", "not available");
4089 if (param->setup.callerinfo.ntype2) {
4090 add_trace("caller id2", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id2, param->setup.callerinfo.ntype2, options.national, options.international));
4091 switch(param->setup.callerinfo.present) {
4092 case INFO_PRESENT_RESTRICTED:
4093 add_trace("caller id2", "present", "restricted");
4095 case INFO_PRESENT_ALLOWED:
4096 add_trace("caller id2", "present", "allowed");
4099 add_trace("caller id2", "present", "not available");
4102 if (param->setup.redirinfo.id[0]) {
4103 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype, options.national, options.international));
4104 switch(param->setup.redirinfo.present) {
4105 case INFO_PRESENT_RESTRICTED:
4106 add_trace("redir'ing", "present", "restricted");
4108 case INFO_PRESENT_ALLOWED:
4109 add_trace("redir'ing", "present", "allowed");
4112 add_trace("redir'ing", "present", "not available");
4115 if (param->setup.dialinginfo.id[0])
4116 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4117 if (param->setup.dialinginfo.keypad[0])
4118 add_trace("keypad", NULL, "%s", param->setup.dialinginfo.keypad);
4119 if (param->setup.dialinginfo.display[0])
4120 add_trace("display", NULL, "%s", param->setup.dialinginfo.display);
4121 if (param->setup.dialinginfo.sending_complete)
4122 add_trace("complete", NULL, "true", param->setup.dialinginfo.sending_complete);
4126 case MESSAGE_OVERLAP:
4127 trace_header("SETUP ACKNOWLEDGE", dir);
4128 if (dir == DIRECTION_OUT)
4129 add_trace("to", NULL, "CH(%lu)", port_id);
4130 if (dir == DIRECTION_IN)
4131 add_trace("from", NULL, "CH(%lu)", port_id);
4135 case MESSAGE_PROCEEDING:
4136 trace_header("PROCEEDING", dir);
4137 if (dir == DIRECTION_OUT)
4138 add_trace("to", NULL, "CH(%lu)", port_id);
4139 if (dir == DIRECTION_IN)
4140 add_trace("from", NULL, "CH(%lu)", port_id);
4144 case MESSAGE_ALERTING:
4145 trace_header("ALERTING", dir);
4146 if (dir == DIRECTION_OUT)
4147 add_trace("to", NULL, "CH(%lu)", port_id);
4148 if (dir == DIRECTION_IN)
4149 add_trace("from", NULL, "CH(%lu)", port_id);
4153 case MESSAGE_CONNECT:
4154 trace_header("CONNECT", dir);
4155 if (dir == DIRECTION_OUT)
4156 add_trace("to", NULL, "CH(%lu)", port_id);
4157 if (dir == DIRECTION_IN)
4158 add_trace("from", NULL, "CH(%lu)", port_id);
4159 if (param->connectinfo.extension[0])
4160 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4161 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype, options.national, options.international));
4162 switch(param->connectinfo.present) {
4163 case INFO_PRESENT_RESTRICTED:
4164 add_trace("connect id", "present", "restricted");
4166 case INFO_PRESENT_ALLOWED:
4167 add_trace("connect id", "present", "allowed");
4170 add_trace("connect id", "present", "not available");
4172 if (param->connectinfo.display[0])
4173 add_trace("display", NULL, "%s", param->connectinfo.display);
4177 case MESSAGE_DISCONNECT:
4178 case MESSAGE_RELEASE:
4179 if (message_type == MESSAGE_DISCONNECT)
4180 trace_header("DISCONNECT", dir);
4182 trace_header("RELEASE", dir);
4183 if (dir == DIRECTION_OUT)
4184 add_trace("to", NULL, "CH(%lu)", port_id);
4185 if (dir == DIRECTION_IN)
4186 add_trace("from", NULL, "CH(%lu)", port_id);
4187 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4188 switch(param->disconnectinfo.location) {
4190 add_trace("cause", "location", "0-User");
4192 case LOCATION_PRIVATE_LOCAL:
4193 add_trace("cause", "location", "1-Local-PBX");
4195 case LOCATION_PUBLIC_LOCAL:
4196 add_trace("cause", "location", "2-Local-Exchange");
4198 case LOCATION_TRANSIT:
4199 add_trace("cause", "location", "3-Transit");
4201 case LOCATION_PUBLIC_REMOTE:
4202 add_trace("cause", "location", "4-Remote-Exchange");
4204 case LOCATION_PRIVATE_REMOTE:
4205 add_trace("cause", "location", "5-Remote-PBX");
4207 case LOCATION_INTERNATIONAL:
4208 add_trace("cause", "location", "7-International-Exchange");
4210 case LOCATION_BEYOND:
4211 add_trace("cause", "location", "10-Beyond-Interworking");
4214 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4216 if (param->disconnectinfo.display[0])
4217 add_trace("display", NULL, "%s", param->disconnectinfo.display);
4221 case MESSAGE_NOTIFY:
4222 switch(param->notifyinfo.notify) {
4227 logtext = "USER_SUSPENDED";
4230 logtext = "BEARER_SERVICE_CHANGED";
4233 logtext = "USER_RESUMED";
4236 logtext = "CONFERENCE_ESTABLISHED";
4239 logtext = "CONFERENCE_DISCONNECTED";
4242 logtext = "OTHER_PARTY_ADDED";
4245 logtext = "ISOLATED";
4248 logtext = "REATTACHED";
4251 logtext = "OTHER_PARTY_ISOLATED";
4254 logtext = "OTHER_PARTY_REATTACHED";
4257 logtext = "OTHER_PARTY_SPLIT";
4260 logtext = "OTHER_PARTY_DISCONNECTED";
4263 logtext = "CONFERENCE_FLOATING";
4266 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4269 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4272 logtext = "CALL_IS_A_WAITING_CALL";
4275 logtext = "DIVERSION_ACTIVATED";
4278 logtext = "RESERVED_CT_1";
4281 logtext = "RESERVED_CT_2";
4284 logtext = "REVERSE_CHARGING";
4287 logtext = "REMOTE_HOLD";
4290 logtext = "REMOTE_RETRIEVAL";
4293 logtext = "CALL_IS_DIVERTING";
4296 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4300 trace_header("NOTIFY", dir);
4301 if (dir == DIRECTION_OUT)
4302 add_trace("to", NULL, "CH(%lu)", port_id);
4303 if (dir == DIRECTION_IN)
4304 add_trace("from", NULL, "CH(%lu)", port_id);
4305 if (param->notifyinfo.notify)
4306 add_trace("indicator", NULL, "%s", logtext);
4307 if (param->notifyinfo.id[0]) {
4308 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype, options.national, options.international));
4309 switch(param->notifyinfo.present) {
4310 case INFO_PRESENT_RESTRICTED:
4311 add_trace("redir'on", "present", "restricted");
4313 case INFO_PRESENT_ALLOWED:
4314 add_trace("redir'on", "present", "allowed");
4317 add_trace("redir'on", "present", "not available");
4320 if (param->notifyinfo.display[0])
4321 add_trace("display", NULL, "%s", param->notifyinfo.display);
4325 case MESSAGE_PROGRESS:
4326 switch(param->progressinfo.progress) {
4328 logtext = "Call is not end to end ISDN";
4331 logtext = "Destination address is non-ISDN";
4334 logtext = "Origination address is non-ISDN";
4337 logtext = "Call has returned to the ISDN";
4340 logtext = "In-band info or pattern available";
4343 SPRINT(buffer, "%d", param->progressinfo.progress);
4347 trace_header("PROGRESS", dir);
4348 if (dir == DIRECTION_OUT)
4349 add_trace("to", NULL, "CH(%lu)", port_id);
4350 if (dir == DIRECTION_IN)
4351 add_trace("from", NULL, "CH(%lu)", port_id);
4352 add_trace("indicator", NULL, "%s", logtext);
4353 switch(param->progressinfo.location) {
4355 add_trace("cause", "location", "0-User");
4357 case LOCATION_PRIVATE_LOCAL:
4358 add_trace("cause", "location", "1-Local-PBX");
4360 case LOCATION_PUBLIC_LOCAL:
4361 add_trace("cause", "location", "2-Local-Exchange");
4363 case LOCATION_TRANSIT:
4364 add_trace("cause", "location", "3-Transit");
4366 case LOCATION_PUBLIC_REMOTE:
4367 add_trace("cause", "location", "4-Remote-Exchange");
4369 case LOCATION_PRIVATE_REMOTE:
4370 add_trace("cause", "location", "5-Remote-PBX");
4372 case LOCATION_INTERNATIONAL:
4373 add_trace("cause", "location", "7-International-Exchange");
4375 case LOCATION_BEYOND:
4376 add_trace("cause", "location", "10-Beyond-Interworking");
4379 add_trace("cause", "location", "%d", param->progressinfo.location);
4384 case MESSAGE_INFORMATION:
4385 trace_header("INFORMATION", dir);
4386 if (dir == DIRECTION_OUT)
4387 add_trace("to", NULL, "CH(%lu)", port_id);
4388 if (dir == DIRECTION_IN)
4389 add_trace("from", NULL, "CH(%lu)", port_id);
4390 if (param->information.id[0])
4391 add_trace("dialing", NULL, "%s", param->information.id);
4392 if (param->information.display[0])
4393 add_trace("display", NULL, "%s", param->information.display);
4394 if (param->information.sending_complete)
4395 add_trace("complete", NULL, "true", param->information.sending_complete);
4399 case MESSAGE_FACILITY:
4400 trace_header("FACILITY", dir);
4401 if (dir == DIRECTION_OUT)
4402 add_trace("to", NULL, "CH(%lu)", port_id);
4403 if (dir == DIRECTION_IN)
4404 add_trace("from", NULL, "CH(%lu)", port_id);
4409 trace_header("TONE", dir);
4410 if (dir == DIRECTION_OUT)
4411 add_trace("to", NULL, "CH(%lu)", port_id);
4412 if (dir == DIRECTION_IN)
4413 add_trace("from", NULL, "CH(%lu)", port_id);
4414 if (param->tone.name[0]) {
4415 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4416 add_trace("name", NULL, "%s", param->tone.name);
4418 add_trace("off", NULL, NULL);
4422 case MESSAGE_SUSPEND:
4423 case MESSAGE_RESUME:
4424 if (message_type == MESSAGE_SUSPEND)
4425 trace_header("SUSPEND", dir);
4427 trace_header("RESUME", dir);
4428 if (dir == DIRECTION_OUT)
4429 add_trace("to", NULL, "CH(%lu)", port_id);
4430 if (dir == DIRECTION_IN)
4431 add_trace("from", NULL, "CH(%lu)", port_id);
4432 if (param->parkinfo.len)
4433 add_trace("length", NULL, "%d", param->parkinfo.len);
4438 case MESSAGE_BCHANNEL:
4439 trace_header("BCHANNEL", dir);
4440 switch(param->bchannel.type) {
4441 case BCHANNEL_REQUEST:
4442 add_trace("type", NULL, "request");
4444 case BCHANNEL_ASSIGN:
4445 add_trace("type", NULL, "assign");
4447 case BCHANNEL_ASSIGN_ACK:
4448 add_trace("type", NULL, "assign_ack");
4450 case BCHANNEL_REMOVE:
4451 add_trace("type", NULL, "remove");
4453 case BCHANNEL_REMOVE_ACK:
4454 add_trace("type", NULL, "remove_ack");
4457 if (param->bchannel.addr)
4458 add_trace("address", NULL, "%x", param->bchannel.addr);
4464 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4468 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, const char *display)
4470 struct lcr_msg *message;
4474 if (!portlist->port_id)
4477 if (!e_connectedmode) {
4478 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4479 message->param.disconnectinfo.cause = cause;
4480 message->param.disconnectinfo.location = location;
4482 SCPY(message->param.disconnectinfo.display, display);
4484 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4486 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4488 SCPY(message->param.notifyinfo.display, display);
4490 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4492 message_put(message);
4493 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);