1 /*****************************************************************************\
3 ** Linux Call Router **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** The EndpointAppPBX implements PBX4Linux **
10 \*****************************************************************************/
15 #include <sys/types.h>
23 class EndpointAppPBX *apppbx_first = NULL;
26 * EndpointAppPBX constructor
28 EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint, int origin) : EndpointApp(epoint, origin)
30 class EndpointAppPBX **apppointer;
32 /* add application to chain */
34 apppointer = &apppbx_first;
36 apppointer = &((*apppointer)->next);
40 memset(&e_ext, 0, sizeof(struct extension));
41 // *************** NOTE: also change value in read_extension() **************
42 e_ext.rights = 4; /* international */
43 e_ext.rx_gain = e_ext.tx_gain = 0;
44 e_state = EPOINT_STATE_IDLE;
45 e_ext.number[0] = '\0';
46 e_extension_interface[0] = '\0';
47 memset(&e_callerinfo, 0, sizeof(struct caller_info));
48 memset(&e_dialinginfo, 0, sizeof(struct dialing_info));
49 memset(&e_connectinfo, 0, sizeof(struct connect_info));
50 memset(&e_redirinfo, 0, sizeof(struct redir_info));
51 memset(&e_capainfo, 0, sizeof(struct capa_info));
54 e_ruleset = ruleset_main;
56 e_rule = e_ruleset->rule_first;
61 e_match_to_action = NULL;
63 e_extdialing = e_dialinginfo.id;
67 // e_join_tone[0] = e_hold_tone[0] = '\0';
68 e_join_pattern /*= e_hold_pattern*/ = 0;
71 e_adminid = 0; // will be set, if call was initiated via admin socket
76 e_cbdialing[0] = '\0';
79 memset(&e_callbackinfo, 0, sizeof(struct caller_info));
86 e_password_timeout = 0;
87 e_multipoint_cause = 0;
88 e_multipoint_location = 0;
89 e_dialing_queue[0] = '\0';
91 e_crypt_state = CM_ST_NULL;
92 e_crypt_keyengine_busy = 0;
93 e_crypt_info[0] = '\0';
96 e_tx_state = NOTIFY_STATE_ACTIVE;
97 e_rx_state = NOTIFY_STATE_ACTIVE;
98 e_join_cause = e_join_location = 0;
99 /*********************************
100 *********************************
101 ********* ATTENTION *************
102 *********************************
103 *********************************/
104 /* if you add new values, that must be initialized, also check if they must
105 * be initialized when doing callback
111 * EpointAppPBX destructor
113 EndpointAppPBX::~EndpointAppPBX(void)
115 class EndpointAppPBX *temp, **tempp;
119 tempp = &apppbx_first;
129 FATAL("Endpoint not in endpoint's list.\n");
136 * trace header for application
138 void EndpointAppPBX::trace_header(char *name, int direction)
142 char msgtext[sizeof(_trace.name)];
146 /* init trace with given values */
149 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype),
153 ea_endpoint->ep_serial,
160 /* set new endpoint state
162 void EndpointAppPBX::new_state(int state)
165 if (e_state != state)
167 trace_header("NEW STATE", DIRECTION_NONE);
168 add_trace("state", "old", "%s", state_name[e_state]);
169 add_trace("state", "new", "%s", state_name[state]);
177 /* release join and port (as specified)
179 void EndpointAppPBX::release(int release, int joinlocation, int joincause, int portlocation, int portcause)
181 struct port_list *portlist;
182 struct message *message;
185 /* message to test call */
186 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", joincause, joinlocation, 0);
188 /* if a release is pending */
189 if (release==RELEASE_JOIN || release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY)
191 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (joincause %d location %d)\n", ea_endpoint->ep_serial, joincause, joinlocation);
192 if (ea_endpoint->ep_join_id)
194 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_RELEASE);
195 message->param.disconnectinfo.cause = joincause;
196 message->param.disconnectinfo.location = joinlocation;
197 message_put(message);
198 ea_endpoint->ep_join_id = 0;
202 if (release != RELEASE_PORT_JOINONLY)
205 join_release(e_hold_id, ea_endpoint->ep_serial, 1, joinlocation, joincause);
210 if (release==RELEASE_ALL || release==RELEASE_PORT_JOINONLY)
212 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
213 while((portlist = ea_endpoint->ep_portlist))
215 if (portlist->port_id)
217 SPRINT(cause, "cause_%02x", portcause);
218 set_tone(portlist, cause);
219 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
220 message->param.disconnectinfo.cause = portcause;
221 message->param.disconnectinfo.location = portlocation;
222 message_put(message);
223 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
225 ea_endpoint->free_portlist(portlist);
228 /* if callback is enabled, call back with the given caller id */
231 /* reset some stuff */
232 new_state(EPOINT_STATE_IDLE);
233 memset(&e_connectinfo, 0, sizeof(struct connect_info));
234 memset(&e_redirinfo, 0, sizeof(struct redir_info));
235 e_start = e_stop = 0;
236 e_ruleset = ruleset_main;
238 e_rule = e_ruleset->rule_first;
240 e_action_timeout = 0;
242 e_match_to_action = NULL;
244 e_extdialing = e_dialinginfo.id;
251 e_multipoint_cause = 0;
252 e_multipoint_location = 0;
253 e_dialing_queue[0] = '\0';
255 e_crypt_state = CM_ST_NULL;
256 e_crypt_keyengine_busy = 0;
257 e_crypt_info[0] = '\0';
261 e_tx_state = NOTIFY_STATE_ACTIVE;
262 e_rx_state = NOTIFY_STATE_ACTIVE;
263 e_join_cause = e_join_location = 0;
265 /* the caller info of the callback user */
266 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
267 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
268 /* create dialing by callerinfo */
269 if (e_ext.number[0] && e_extension_interface[0])
271 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
272 /* create callback to the current terminal */
273 SCPY(e_dialinginfo.id, e_ext.number);
274 SCPY(e_dialinginfo.interfaces, e_extension_interface);
275 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
276 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
281 SCPY(e_dialinginfo.id, e_cbto);
284 /* numberrize caller id and use it to dial to the callback */
285 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype));
287 e_dialinginfo.itype = INFO_ITYPE_ISDN;
288 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
289 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
294 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
295 ea_endpoint->ep_use--; /* when e_lock is 0, the endpoint will be deleted */
301 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
302 void apply_callerid_restriction(struct extension *ext, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
304 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");
306 /* caller id is not restricted, so we do nothing */
307 if (*present != INFO_PRESENT_RESTRICTED)
310 /* only extensions are restricted */
314 /* if we enabled anonymouse ignore */
315 if (ext->anon_ignore)
318 /* else we remove the caller id */
322 *ntype = INFO_NTYPE_UNKNOWN;
324 // *screen = INFO_SCREEN_USER;
325 // maybe we should not make voip address anonymous
328 // maybe it's no fraud to present extension id
330 // extension[0] = '\0';
335 /* used display message to display callerid as available */
336 char *EndpointAppPBX::apply_callerid_display(char *id, int itype, int ntype, int present, int screen, char *extension, char *name)
338 static char display[81];
341 char *cid = numberrize_callerinfo(id, ntype);
343 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");
352 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
354 /* internal extension's caller id */
355 if (extension[0] && e_ext.display_int)
358 SCAT(display, extension);
361 if (itype == INFO_ITYPE_VBOX)
362 SCAT(display, "(vbox)");
364 SCAT(display, "(int)");
367 /* external caller id */
368 if (!extension[0] && e_ext.display_ext)
374 if (present == INFO_PRESENT_RESTRICTED)
375 SCAT(display, "anonymous");
377 SCAT(display, "unknown");
384 /* display if callerid is anonymouse but available due anon-ignore */
385 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED)
388 SCAT(display, "unknown");
391 SCAT(display, " anon");
394 /* display if callerid is anonymouse but available due anon-ignore */
395 if (e_ext.display_fake && screen==INFO_SCREEN_USER && present!=INFO_PRESENT_NULL)
401 if (present == INFO_PRESENT_RESTRICTED)
402 SCAT(display, "anonymous");
404 SCAT(display, "unknown");
409 SCAT(display, " fake");
413 if (name[0] && e_ext.display_name)
415 if (!display[0] && cid[0])
426 * uses the current state to notify activity
428 void EndpointAppPBX::notify_active(void)
430 struct port_list *portlist = ea_endpoint->ep_portlist;
431 struct message *message;
436 case NOTIFY_STATE_ACTIVE:
437 /* we are already active, so we don't do anything */
440 case NOTIFY_STATE_SUSPEND:
441 notify = INFO_NOTIFY_USER_RESUMED;
444 set_tone(portlist, NULL);
445 portlist = portlist->next;
447 portlist = ea_endpoint->ep_portlist;
450 case NOTIFY_STATE_HOLD:
451 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
454 set_tone(portlist, NULL);
455 portlist = portlist->next;
457 portlist = ea_endpoint->ep_portlist;
460 case NOTIFY_STATE_CONFERENCE:
461 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
464 set_tone(portlist, NULL);
465 portlist = portlist->next;
467 portlist = ea_endpoint->ep_portlist;
471 PERROR("unknown e_tx_state = %d\n", e_tx_state);
477 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
478 message->param.notifyinfo.notify = notify;
479 message_put(message);
480 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
481 portlist = portlist->next;
487 * keypad functions during call. one example to use this is to put a call on hold or start a conference
489 void EndpointAppPBX::keypad_function(char digit)
492 /* we must be in a call, in order to send messages to the call */
493 if (e_ext.number[0] == '\0')
495 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
501 /* join conference */
503 if (ea_endpoint->ep_join_id == 0)
505 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
508 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
514 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
518 /* crypt key-exchange */
520 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
526 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
531 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
536 /* set tone pattern for port */
537 void EndpointAppPBX::set_tone(struct port_list *portlist, char *tone)
539 struct message *message;
544 /* store for suspended processes */
548 if (e_join_pattern /* pattern are provided */
549 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
550 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
551 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
552 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
553 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
554 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
555 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
556 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
557 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
558 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
559 && tone[0] && !!strncmp(tone,"crypt_*",6))
561 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
567 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
568 SCPY(message->param.tone.dir, e_ext.tones_dir[0]?e_ext.tones_dir:options.tones_dir);
569 SCPY(message->param.tone.name, tone);
570 message_put(message);
571 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
574 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port to notify tone.\n", ea_endpoint->ep_serial);
581 * hunts an mISDNport that is available for an outgoing call
582 * if no ifname was given, any interface that is not an extension
585 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
587 struct interface *interface;
588 struct interface_port *ifport, *ifport_start;
589 struct select_channel *selchannel;
590 struct mISDNport *mISDNport;
593 interface = interface_first;
595 /* first find the given interface or, if not given, one with no extension */
600 /* check for given interface */
603 if (!strcasecmp(interface->name, ifname))
605 /* found explicit interface */
606 trace_header("CHANNEL SELECTION (found interface)", DIRECTION_NONE);
607 add_trace("interface", NULL, "%s", ifname);
614 if (!interface->extension)
616 /* found non extension */
617 trace_header("CHANNEL SELECTION (found non extension interface)", DIRECTION_NONE);
618 add_trace("interface", NULL, "%s", interface->name);
624 interface = interface->next;
628 /* see if interface has ports */
629 if (!interface->ifport)
632 trace_header("CHANNEL SELECTION (interface has no active ports, skipping)", DIRECTION_NONE);
633 add_trace("interface", NULL, "%s", interface->name);
635 interface = interface->next;
639 /* select port by algorithm */
640 ifport_start = interface->ifport;
642 if (interface->hunt == HUNT_ROUNDROBIN)
644 while(ifport_start->next && index<interface->hunt_next)
646 ifport_start = ifport_start->next;
649 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
650 add_trace("port", NULL, "%d", ifport_start->portnum);
651 add_trace("position", NULL, "%d", index);
656 ifport = ifport_start;
659 /* see if port is available */
660 if (!ifport->mISDNport)
662 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
663 add_trace("port", NULL, "%d", ifport->portnum);
664 add_trace("position", NULL, "%d", index);
668 mISDNport = ifport->mISDNport;
670 /* see if port is administratively blocked */
673 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
674 add_trace("port", NULL, "%d", ifport->portnum);
675 add_trace("position", NULL, "%d", index);
680 /* see if link is up on PTP*/
681 if (mISDNport->ptp && !mISDNport->l2link)
683 trace_header("CHANNEL SELECTION (port is ptp with layer 2 down, skipping)", DIRECTION_NONE);
684 add_trace("port", NULL, "%d", ifport->portnum);
685 add_trace("position", NULL, "%d", index);
690 /* check for channel form selection list */
692 selchannel = ifport->out_channel;
695 switch(selchannel->channel)
697 case CHANNEL_FREE: /* free channel */
698 if (mISDNport->b_reserved >= mISDNport->b_num)
699 break; /* all channel in use or reserverd */
702 while(i < mISDNport->b_num)
704 if (mISDNport->b_port[i] == NULL)
706 *channel = i+1+(i>=15);
707 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
708 add_trace("port", NULL, "%d", ifport->portnum);
709 add_trace("position", NULL, "%d", index);
710 add_trace("channel", NULL, "%d", *channel);
718 trace_header("CHANNEL SELECTION (no channel is 'free')", DIRECTION_NONE);
719 add_trace("port", NULL, "%d", ifport->portnum);
720 add_trace("position", NULL, "%d", index);
724 case CHANNEL_ANY: /* don't ask for channel */
725 if (mISDNport->b_reserved >= mISDNport->b_num)
727 trace_header("CHANNEL SELECTION (cannot ask for 'any' channel, all reserved)", DIRECTION_NONE);
728 add_trace("port", NULL, "%d", ifport->portnum);
729 add_trace("position", NULL, "%d", index);
730 add_trace("total", NULL, "%d", mISDNport->b_num);
731 add_trace("reserved", NULL, "%d", mISDNport->b_reserved);
733 break; /* all channel in use or reserverd */
735 trace_header("CHANNEL SELECTION (using 'any' channel)", DIRECTION_NONE);
736 add_trace("port", NULL, "%d", ifport->portnum);
737 add_trace("position", NULL, "%d", index);
739 *channel = CHANNEL_ANY;
742 case CHANNEL_NO: /* call waiting */
743 trace_header("CHANNEL SELECTION (using 'no' channel, call-waiting)", DIRECTION_NONE);
744 add_trace("port", NULL, "%d", ifport->portnum);
745 add_trace("position", NULL, "%d", index);
747 *channel = CHANNEL_NO;
751 if (selchannel->channel<1 || selchannel->channel==16)
753 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
754 add_trace("port", NULL, "%d", ifport->portnum);
755 add_trace("position", NULL, "%d", index);
756 add_trace("channel", NULL, "%d", selchannel->channel);
758 break; /* invalid channels */
760 i = selchannel->channel-1-(selchannel->channel>=17);
761 if (i >= mISDNport->b_num)
763 trace_header("CHANNEL SELECTION (channel out of range)", DIRECTION_NONE);
764 add_trace("port", NULL, "%d", ifport->portnum);
765 add_trace("position", NULL, "%d", index);
766 add_trace("channel", NULL, "%d", selchannel->channel);
767 add_trace("channels", NULL, "%d", mISDNport->b_num);
769 break; /* channel not in port */
771 if (mISDNport->b_port[i] == NULL)
773 *channel = selchannel->channel;
774 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
775 add_trace("port", NULL, "%d", ifport->portnum);
776 add_trace("position", NULL, "%d", index);
777 add_trace("channel", NULL, "%d", *channel);
784 break; /* found channel */
785 selchannel = selchannel->next;
788 /* if channel was found, return mISDNport and channel */
791 /* setting next port to start next time */
792 if (interface->hunt == HUNT_ROUNDROBIN)
797 interface->hunt_next = index;
803 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
804 add_trace("port", NULL, "%d", ifport->portnum);
805 add_trace("position", NULL, "%d", index);
809 /* go next port, until all ports are checked */
811 ifport = ifport->next;
815 ifport = interface->ifport;
817 if (ifport != ifport_start)
820 return(NULL); /* no port found */
823 /* outgoing setup to port(s)
824 * ports will be created and a setup is sent if everything is ok. otherwhise
825 * the endpoint is destroyed.
827 void EndpointAppPBX::out_setup(void)
829 struct dialing_info dialinginfo;
831 // class pdss1 *pdss1;
832 struct port_list *portlist;
833 struct message *message;
835 int cause = CAUSE_RESSOURCEUNAVAIL;
838 struct mISDNport *mISDNport;
841 class EndpointAppPBX *atemp;
842 // char allowed_ports[256];
844 char ifname[sizeof(e_ext.interfaces)],
846 struct port_settings port_settings;
850 /* create settings for creating port */
851 memset(&port_settings, 0, sizeof(port_settings));
853 SCPY(port_settings.tones_dir, e_ext.tones_dir);
855 SCPY(port_settings.tones_dir, options.tones_dir);
856 port_settings.no_seconds = e_ext.no_seconds;
858 /* 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 */
860 /* check what dialinginfo.itype we got */
861 switch(e_dialinginfo.itype)
863 /* *********************** call to extension or vbox */
864 case INFO_ITYPE_ISDN_EXTENSION:
865 /* check if we deny incoming calls when we use an extension */
866 if (e_ext.noknocking)
868 atemp = apppbx_first;
872 if (!strcmp(atemp->e_ext.number, e_ext.number))
878 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
879 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYSPE_ join, port */
880 return; /* must exit here */
883 /* FALL THROUGH !!!! */
884 case INFO_ITYPE_VBOX:
885 /* get dialed extension's info */
886 // SCPY(exten, e_dialinginfo.id);
887 // if (strchr(exten, ','))
888 // *strchr(exten, ',') = '\0';
889 // if (!read_extension(&e_ext, exten))
890 if (!read_extension(&e_ext, e_dialinginfo.id))
892 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
893 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
894 return; /* must exit here */
897 if (e_dialinginfo.itype == INFO_ITYPE_VBOX)
899 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
904 /* string from unconditional call forward (cfu) */
908 /* present to forwarded party */
909 if (e_ext.anon_ignore && e_callerinfo.id[0])
911 e_callerinfo.present = INFO_PRESENT_ALLOWED;
913 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
917 /* string from busy call forward (cfb) */
921 class EndpointAppPBX *checkapp = apppbx_first;
924 if (checkapp != this) /* any other endpoint except our own */
926 if (!strcmp(checkapp->e_ext.number, e_ext.number))
928 /* present to forwarded party */
929 if (e_ext.anon_ignore && e_callerinfo.id[0])
931 e_callerinfo.present = INFO_PRESENT_ALLOWED;
933 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
937 checkapp = checkapp->next;
941 /* string from no-response call forward (cfnr) */
945 /* when cfnr is done, out_setup() will setup the call */
948 /* present to forwarded party */
949 if (e_ext.anon_ignore && e_callerinfo.id[0])
951 e_callerinfo.present = INFO_PRESENT_ALLOWED;
955 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
957 e_cfnr_release = now + e_ext.cfnr_delay;
958 e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */
959 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);
963 /* call to all internal interfaces */
964 p = e_ext.interfaces;
965 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple joins for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
969 while(*p!=',' && *p!='\0')
974 /* found interface */
975 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
976 /* hunt for mISDNport and create Port */
977 mISDNport = hunt_port(ifname, &channel);
980 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
981 add_trace("interface", NULL, "%s", ifname);
985 /* creating INTERNAL port */
986 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
987 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force);
989 FATAL("No memory for DSS1 Port instance\n");
990 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
991 memset(&dialinginfo, 0, sizeof(dialinginfo));
992 SCPY(dialinginfo.id, e_dialinginfo.id);
993 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
994 dialinginfo.ntype = e_dialinginfo.ntype;
995 /* create port_list relation */
996 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
999 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1001 goto check_anycall_intern;
1003 /* directory.list */
1004 if (e_callerinfo.id[0] && e_ext.display_name)
1006 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1008 SCPY(e_callerinfo.name, dirname);
1010 // dss1 = (class Pdss1 *)port;
1012 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1013 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1014 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1015 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1016 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1017 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1018 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1019 //terminal if (e_dialinginfo.id)
1020 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1021 /* handle restricted caller ids */
1022 apply_callerid_restriction(&e_ext, message->param.setup.callerinfo.id, &message->param.setup.callerinfo.ntype, &message->param.setup.callerinfo.present, &message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name);
1023 apply_callerid_restriction(&e_ext, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1024 /* display callerid if desired for extension */
1025 SCPY(message->param.setup.callerinfo.display, apply_callerid_display(message->param.setup.callerinfo.id, message->param.setup.callerinfo.itype, message->param.setup.callerinfo.ntype, message->param.setup.callerinfo.present, message->param.setup.callerinfo.screen, message->param.setup.callerinfo.extension, message->param.setup.callerinfo.name));
1026 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1027 /* use cnip, if enabld */
1028 // if (!e_ext.centrex)
1029 // message->param.setup.callerinfo.name[0] = '\0';
1030 /* screen clip if prefix is required */
1031 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0])
1033 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1034 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype));
1035 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1037 /* use internal caller id */
1038 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore))
1040 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1041 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1043 message_put(message);
1044 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1048 /* string from parallel call forward (cfp) */
1052 if (e_ext.anon_ignore && e_callerinfo.id[0])
1054 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1058 vbox_only: /* entry point for answering machine only */
1059 cfu_only: /* entry point for cfu */
1060 cfb_only: /* entry point for cfb */
1061 cfnr_only: /* entry point for cfnr */
1062 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1067 /* only if vbox should be dialed, and terminal is given */
1068 if (!strcmp(p, "vbox") && e_ext.number[0])
1070 /* go to the end of p */
1073 /* answering vbox call */
1074 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1076 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1077 FATAL("No memory for VBOX Port instance\n");
1078 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1079 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1083 while(*p!=',' && *p!='\0')
1088 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1089 /* hunt for mISDNport and create Port */
1090 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1093 /* creating EXTERNAL port*/
1094 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1095 if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force)))
1096 FATAL("No memory for DSS1 Port instance\n");
1097 earlyb = mISDNport->earlyb;
1101 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1102 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1108 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1109 goto check_anycall_intern;
1111 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1112 memset(&dialinginfo, 0, sizeof(dialinginfo));
1113 SCPY(dialinginfo.id, cfp);
1114 dialinginfo.itype = INFO_ITYPE_ISDN;
1115 dialinginfo.ntype = e_dialinginfo.ntype;
1116 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1119 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1121 goto check_anycall_intern;
1123 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1124 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1125 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1126 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1127 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1128 /* if clip is hidden */
1129 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT)
1131 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1132 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1133 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1134 message->param.setup.callerinfo.present = e_ext.callerid_present;
1136 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1137 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1138 //terminal if (e_dialinginfo.id)
1139 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1140 /* handle restricted caller ids */
1141 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);
1142 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);
1143 /* display callerid if desired for extension */
1144 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));
1145 message_put(message);
1146 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1150 check_anycall_intern:
1151 /* now we have all ports created */
1154 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1156 if (!ea_endpoint->ep_join_id)
1158 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1159 return; /* must exit here */
1163 /* *********************** external call */
1165 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id);
1166 /* call to extenal interfaces */
1167 p = e_dialinginfo.id;
1171 while(*p!=',' && *p!='\0')
1172 SCCAT(number, *p++);
1176 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");
1177 /* hunt for mISDNport and create Port */
1178 /* hunt for mISDNport and create Port */
1179 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1182 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1183 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1185 goto check_anycall_extern;
1187 /* creating EXTERNAL port*/
1188 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1189 if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force)))
1190 FATAL("No memory for DSS1 Port instance\n");
1191 earlyb = mISDNport->earlyb;
1192 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1193 memset(&dialinginfo, 0, sizeof(dialinginfo));
1194 SCPY(dialinginfo.id, number);
1195 dialinginfo.itype = INFO_ITYPE_ISDN;
1196 dialinginfo.ntype = e_dialinginfo.ntype;
1197 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1200 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1202 goto check_anycall_extern;
1204 // dss1 = (class Pdss1 *)port;
1205 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1206 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1207 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1208 SCPY(message->param.setup.dialinginfo.id, number);
1209 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1210 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1211 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1212 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1213 //terminal if (e_dialinginfo.id)
1214 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1215 /* handle restricted caller ids */
1216 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);
1217 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);
1218 /* display callerid if desired for extension */
1219 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));
1220 message_put(message);
1221 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1225 check_anycall_extern:
1226 /* now we have all ports created */
1229 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1231 if (!ea_endpoint->ep_join_id)
1233 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1234 return; /* must exit here */
1242 /* handler for endpoint
1246 int EndpointAppPBX::handler(void)
1248 if (e_crypt_state!=CM_ST_NULL)
1253 /* process answering machine (play) handling */
1256 if (e_action->index == ACTION_VBOX_PLAY)
1259 /* process action timeout */
1260 if (e_action_timeout)
1261 if (now_d >= e_action_timeout)
1263 if (e_state!=EPOINT_STATE_CONNECT)
1266 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea_endpoint->ep_serial);
1267 e_multipoint_cause = 0;
1268 e_multipoint_location = 0;
1269 new_state(EPOINT_STATE_IN_OVERLAP);
1272 return(1); /* we must exit, because our endpoint might be gone */
1274 e_action_timeout = 0;
1277 /* process action timeout */
1278 if (e_match_timeout)
1279 if (now_d >= e_match_timeout)
1282 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea_endpoint->ep_serial);
1284 return(1); /* we must exit, because our endpoint might be gone */
1289 /* process redialing (epoint redials to port) */
1292 if (now_d >= e_redial)
1295 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea_endpoint->ep_serial);
1297 new_state(EPOINT_STATE_OUT_SETUP);
1298 /* call special setup routine */
1305 /* process powerdialing (epoint redials to epoint) */
1306 if (e_powerdialing > 0)
1308 if (now_d >= e_powerdialing)
1310 e_powerdialing = -1; /* leave power dialing on */
1311 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea_endpoint->ep_serial);
1314 e_ruleset = ruleset_main;
1316 e_rule = e_ruleset->rule_first;
1318 new_state(EPOINT_STATE_IN_OVERLAP);
1324 /* process call forward no response */
1327 struct port_list *portlist;
1328 struct message *message;
1330 if (now >= e_cfnr_release)
1332 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea_endpoint->ep_serial);
1335 /* release all ports */
1336 while((portlist = ea_endpoint->ep_portlist))
1338 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1339 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1340 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1341 message_put(message);
1342 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1343 ea_endpoint->free_portlist(portlist);
1346 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1347 message->param.audiopath = CHANNEL_STATE_HOLD;
1348 message_put(message);
1349 /* indicate no patterns */
1350 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1351 message_put(message);
1352 /* set setup state, since we have no response from the new join */
1353 new_state(EPOINT_STATE_OUT_SETUP);
1358 if (now >= e_cfnr_call)
1360 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea_endpoint->ep_serial, e_ext.cfnr);
1366 /* handle connection to user */
1367 if (e_state == EPOINT_STATE_IDLE)
1369 /* epoint is idle, check callback */
1371 if (now_d >= e_callback)
1373 e_callback = 0; /* done with callback */
1374 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea_endpoint->ep_serial);
1375 new_state(EPOINT_STATE_OUT_SETUP);
1381 /* check for password timeout */
1383 if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE)
1385 struct port_list *portlist;
1387 if (now >= e_password_timeout)
1389 e_ruleset = ruleset_main;
1391 e_rule = e_ruleset->rule_first;
1393 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea_endpoint->ep_serial, e_extdialing);
1394 trace_header("PASSWORD timeout", DIRECTION_NONE);
1396 e_connectedmode = 0;
1398 new_state(EPOINT_STATE_OUT_DISCONNECT);
1399 portlist = ea_endpoint->ep_portlist;
1402 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1403 set_tone(portlist, "cause_10");
1413 /* doing a hookflash */
1414 void EndpointAppPBX::hookflash(void)
1418 /* be sure that we are active */
1420 e_tx_state = NOTIFY_STATE_ACTIVE;
1422 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1424 if (ea_endpoint->ep_use > 1)
1426 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1429 /* dialtone after pressing the hash key */
1430 process_hangup(e_join_cause, e_join_location);
1431 e_multipoint_cause = 0;
1432 e_multipoint_location = 0;
1433 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1436 port->set_echotest(0);
1438 if (ea_endpoint->ep_join_id)
1440 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
1442 e_ruleset = ruleset_main;
1444 e_rule = e_ruleset->rule_first;
1446 new_state(EPOINT_STATE_IN_OVERLAP);
1447 e_connectedmode = 1;
1448 SCPY(e_dialinginfo.id, e_ext.prefix);
1449 e_extdialing = e_dialinginfo.id;
1451 if (e_dialinginfo.id[0])
1453 set_tone(ea_endpoint->ep_portlist, "dialing");
1457 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1464 /* messages from port
1466 /* port MESSAGE_SETUP */
1467 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1469 struct message *message;
1471 int writeext; /* flags need to write extension after modification */
1473 struct interface *interface;
1475 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1477 portlist->port_type = param->setup.port_type;
1478 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1479 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1480 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1481 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1482 e_dtmf = param->setup.dtmf;
1483 /* screen incoming caller id */
1484 interface = interface_first;
1487 if (!strcmp(e_callerinfo.interface, interface->name))
1491 interface = interface->next;
1494 do_screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present, interface);
1496 /* process extension */
1497 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1499 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1500 /* port makes call from extension */
1501 SCPY(e_callerinfo.extension, e_callerinfo.id);
1502 SCPY(e_ext.number, e_callerinfo.extension);
1503 SCPY(e_extension_interface, e_callerinfo.interface);
1506 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1509 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1511 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1513 /* get extension's info about caller */
1514 if (!read_extension(&e_ext, e_ext.number))
1516 /* extension doesn't exist */
1517 trace_header("EXTENSION (not created)", DIRECTION_IN);
1518 add_trace("extension", NULL, "%s", e_ext.number);
1520 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1521 new_state(EPOINT_STATE_OUT_DISCONNECT);
1522 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1523 e_ext.number[0] = '\0'; /* no terminal */
1528 /* put prefix (next) in front of e_dialinginfo.id */
1531 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1532 SCPY(e_dialinginfo.id, buffer);
1533 e_ext.next[0] = '\0';
1535 } else if (e_ext.prefix[0])
1537 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1538 SCPY(e_dialinginfo.id, buffer);
1541 /* screen caller id by extension's config */
1542 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1544 SCPY(e_callerinfo.name, e_ext.name);
1545 /* use caller id (or if exist: id_next_call) for this call */
1546 if (e_ext.id_next_call_present >= 0)
1548 SCPY(e_callerinfo.id, e_ext.id_next_call);
1549 /* if we restrict the pesentation */
1550 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1551 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1552 else e_callerinfo.present = e_ext.id_next_call_present;
1553 e_callerinfo.ntype = e_ext.id_next_call_type;
1554 e_ext.id_next_call_present = -1;
1558 SCPY(e_callerinfo.id, e_ext.callerid);
1559 /* if we restrict the pesentation */
1560 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1561 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1562 else e_callerinfo.present = e_ext.callerid_present;
1563 e_callerinfo.ntype = e_ext.callerid_type;
1566 /* extension is written */
1568 write_extension(&e_ext, e_ext.number);
1570 /* set volume of rx and tx */
1571 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1572 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
1574 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1575 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1576 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
1577 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
1578 message_put(message);
1581 /* start recording if enabled */
1582 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO))
1584 /* check if we are a terminal */
1585 if (e_ext.number[0] == '\0')
1586 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1589 port = find_port_id(portlist->port_id);
1591 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1596 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1597 /* no terminal identification */
1598 e_ext.number[0] = '\0';
1599 e_extension_interface[0] = '\0';
1600 memset(&e_ext, 0, sizeof(e_ext));
1601 e_ext.rights = 4; /* right to dial internat */
1605 e_ruleset = ruleset_main;
1607 e_rule = e_ruleset->rule_first;
1609 e_extdialing = e_dialinginfo.id;
1610 new_state(EPOINT_STATE_IN_SETUP);
1611 if (e_dialinginfo.id[0])
1613 set_tone(portlist, "dialing");
1616 if (e_ext.number[0])
1617 set_tone(portlist, "dialpbx");
1619 set_tone(portlist, "dialtone");
1622 if (e_state == EPOINT_STATE_IN_SETUP)
1624 /* request MORE info, if not already at higher state */
1625 new_state(EPOINT_STATE_IN_OVERLAP);
1626 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1627 message_put(message);
1628 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
1632 /* port MESSAGE_INFORMATION */
1633 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1635 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1639 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1642 trace_header("DTMF (disabling due to keypad)", DIRECTION_IN);
1647 /* if vbox_play is done, the information are just used as they come */
1649 if (e_action->index == ACTION_VBOX_PLAY)
1651 /* concat dialing string */
1652 SCAT(e_dialinginfo.id, param->information.id);
1657 /* keypad when disconnect but in connected mode */
1658 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode)
1660 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1661 /* processing keypad function */
1662 if (param->information.id[0] == '0')
1669 /* keypad when connected */
1670 if (e_state == EPOINT_STATE_CONNECT)
1674 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1675 /* processing keypad function */
1676 if (param->information.id[0] == '0')
1680 if (param->information.id[0])
1681 keypad_function(param->information.id[0]);
1684 if (e_ext.number[0])
1685 trace_header("KEYPAD (not enabled by extension's settings)", DIRECTION_IN);
1687 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1692 if (e_state != EPOINT_STATE_IN_OVERLAP)
1694 if (e_ext.number[0])
1695 trace_header("KEYPAD (ignored, not connected and not dialing)", DIRECTION_IN);
1697 trace_header("KEYPAD (not enabled for external interfaces)", DIRECTION_IN);
1701 if (!param->information.id[0])
1703 if (e_dialinginfo.id[0]=='\0' && !e_action)
1705 set_tone(portlist, "dialing");
1708 if (e_action->index==ACTION_OUTDIAL
1709 || e_action->index==ACTION_EXTERNAL)
1712 set_tone(portlist, "dialing");
1713 else if (!e_extdialing[0])
1714 set_tone(portlist, "dialing");
1716 /* concat dialing string */
1717 SCAT(e_dialinginfo.id, param->information.id);
1721 /* port MESSAGE_DTMF */
1722 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1724 /* only if dtmf detection is enabled */
1727 trace_header("DTMF (disabled)", DIRECTION_IN);
1731 trace_header("DTMF", DIRECTION_IN);
1732 add_trace("digit", NULL, "%c", param->dtmf);
1736 NOTE: vbox is now handled due to overlap state
1737 /* if vbox_play is done, the dtmf digits are just used as they come */
1739 if (e_action->index == ACTION_VBOX_PLAY)
1741 /* concat dialing string */
1742 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id))
1744 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1745 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1748 /* continue to process *X# sequences */
1752 /* check for *X# sequence */
1753 if (e_state == EPOINT_STATE_CONNECT)
1755 if (e_dtmf_time+3 < now)
1757 /* the last digit was too far in the past to be a sequence */
1758 if (param->dtmf == '*')
1759 /* only start is allowed in the sequence */
1765 /* we have a sequence of digits, see what we got */
1766 if (param->dtmf == '*')
1768 else if (param->dtmf>='0' && param->dtmf<='9')
1770 /* we need to have a star before we receive the digit of the sequence */
1771 if (e_dtmf_last == '*')
1772 e_dtmf_last = param->dtmf;
1773 } else if (param->dtmf == '#')
1776 if (e_dtmf_last>='0' && e_dtmf_last<='9')
1778 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1779 if (e_dtmf_last == '0')
1784 /* processing keypad function */
1786 keypad_function(e_dtmf_last);
1792 /* set last time of dtmf */
1797 /* check for ## hookflash during dialing */
1799 if (e_action->index==ACTION_PASSWORD
1800 || e_action->index==ACTION_PASSWORD_WRITE)
1802 if (param->dtmf=='#') /* current digit is '#' */
1804 if (e_state==EPOINT_STATE_IN_DISCONNECT
1805 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) /* when disconnected, just #. when dialing, ##. */
1822 /* dialing using dtmf digit */
1823 if (e_state==EPOINT_STATE_IN_OVERLAP)// && e_state==e_connectedmode)
1825 if (e_dialinginfo.id[0]=='\0' && !e_action)
1827 set_tone(portlist, "dialing");
1829 /* concat dialing string */
1830 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id))
1832 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1833 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1839 /* port MESSAGE_CRYPT */
1840 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1842 /* send crypt response to cryptman */
1843 if (param->crypt.type == CR_MESSAGE_IND)
1844 cryptman_msg2man(param->crypt.data, param->crypt.len);
1846 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
1849 /* port MESSAGE_OVERLAP */
1850 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
1852 struct message *message;
1854 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1856 /* signal to call tool */
1857 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
1859 if (e_dialing_queue[0] && portlist)
1861 /* send what we have not dialed yet, because we had no setup complete */
1862 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
1863 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
1864 SCPY(message->param.information.id, e_dialing_queue);
1865 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
1866 message_put(message);
1867 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
1868 e_dialing_queue[0] = '\0';
1870 /* check if pattern is available */
1871 if (!ea_endpoint->ep_portlist->next && portlist->early_b) /* one port_list relation and tones available */
1873 /* indicate patterns */
1874 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1875 message_put(message);
1877 /* connect audio, if not already */
1878 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1879 message->param.audiopath = CHANNEL_STATE_CONNECT;
1880 message_put(message);
1883 /* indicate no patterns */
1884 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1885 message_put(message);
1887 /* disconnect audio, if not already */
1888 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1889 message->param.audiopath = CHANNEL_STATE_HOLD;
1890 message_put(message);
1892 new_state(EPOINT_STATE_OUT_OVERLAP);
1893 /* if we are in a join */
1894 if (ea_endpoint->ep_join_id)
1896 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1897 memcpy(&message->param, param, sizeof(union parameter));
1898 message_put(message);
1902 /* port MESSAGE_PROCEEDING */
1903 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
1905 struct message *message;
1907 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1909 /* signal to call tool */
1910 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
1912 e_state = EPOINT_STATE_OUT_PROCEEDING;
1913 /* check if pattern is availatle */
1914 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) /* one port_list relation and tones available */
1916 /* indicate patterns */
1917 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1918 message_put(message);
1920 /* connect audio, if not already */
1921 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1922 message->param.audiopath = CHANNEL_STATE_CONNECT;
1923 message_put(message);
1926 /* indicate no patterns */
1927 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1928 message_put(message);
1930 /* disconnect audio, if not already */
1931 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1932 message->param.audiopath = CHANNEL_STATE_HOLD;
1933 message_put(message);
1935 /* if we are in a call */
1936 if (ea_endpoint->ep_join_id)
1938 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1939 memcpy(&message->param, param, sizeof(union parameter));
1940 message_put(message);
1944 /* port MESSAGE_ALERTING */
1945 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
1947 struct message *message;
1949 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1951 /* signal to call tool */
1952 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
1954 new_state(EPOINT_STATE_OUT_ALERTING);
1955 /* check if pattern is available */
1956 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) /* one port_list relation and tones available */
1958 /* indicate patterns */
1959 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
1960 message_put(message);
1962 /* connect audio, if not already */
1963 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1964 message->param.audiopath = CHANNEL_STATE_CONNECT;
1965 message_put(message);
1968 /* indicate no patterns */
1969 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOPATTERN);
1970 message_put(message);
1972 /* disconnect audio, if not already */
1973 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
1974 message->param.audiopath = CHANNEL_STATE_HOLD;
1975 message_put(message);
1977 /* if we are in a call */
1978 if (ea_endpoint->ep_join_id)
1980 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
1981 memcpy(&message->param, param, sizeof(union parameter));
1982 message_put(message);
1986 /* port MESSAGE_CONNECT */
1987 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
1989 struct message *message;
1991 unsigned long port_id = portlist->port_id;
1992 struct port_list *tportlist;
1994 struct interface *interface;
1996 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
1998 /* signal to call tool */
1999 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype), 0, 0, 0);
2001 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
2002 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2003 while(ea_endpoint->ep_portlist->next) /* as long as we have at least two ports */
2005 tportlist = ea_endpoint->ep_portlist;
2006 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2007 tportlist = tportlist->next;
2008 if (tportlist->port_id == port_id)
2009 FATAL("EPOINT(%d) this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2010 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2011 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
2012 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2013 message_put(message);
2014 logmessage(message->type, &message->param, tportlist->port_id, DIRECTION_OUT);
2015 ea_endpoint->free_portlist(tportlist);
2017 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2021 /* screen incoming connected id */
2022 interface = interface_first;
2025 if (!strcmp(e_connectinfo.interface, interface->name))
2029 interface = interface->next;
2032 do_screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present, interface);
2034 /* screen connected name */
2036 SCPY(e_connectinfo.name, e_ext.name);
2038 /* add internal id to colp */
2039 SCPY(e_connectinfo.extension, e_ext.number);
2041 /* we store the connected port number */
2042 SCPY(e_extension_interface, e_connectinfo.interface);
2044 /* for internal and am calls, we get the extension's id */
2045 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE)
2047 SCPY(e_connectinfo.id, e_ext.callerid);
2048 SCPY(e_connectinfo.extension, e_ext.number);
2049 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2050 e_connectinfo.ntype = e_ext.callerid_type;
2051 e_connectinfo.present = e_ext.callerid_present;
2053 if (portlist->port_type==PORT_TYPE_VBOX_OUT)
2055 e_connectinfo.itype = INFO_ITYPE_VBOX;
2056 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2059 new_state(EPOINT_STATE_CONNECT);
2061 /* set volume of rx and tx */
2062 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2064 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2065 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2066 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2067 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2068 message_put(message);
2071 e_cfnr_call = e_cfnr_release = 0;
2072 if (e_ext.number[0])
2073 e_dtmf = 1; /* allow dtmf */
2076 /* other calls with no caller id (or not available for the extension) and force colp */
2077 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE)
2079 e_connectinfo.present = INFO_PRESENT_NOTAVAIL;
2080 if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) /* external extension answered */
2082 port = find_port_id(portlist->port_id);
2085 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype));
2086 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2091 /* send connect to join */
2092 if (ea_endpoint->ep_join_id)
2094 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2095 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2096 message_put(message);
2098 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2099 message->param.audiopath = CHANNEL_STATE_CONNECT;
2100 message_put(message);
2101 } else if (!e_adminid)
2104 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2105 SCPY(e_ext.number, e_cbcaller);
2106 new_state(EPOINT_STATE_IN_OVERLAP);
2107 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2109 /* get extension's info about terminal */
2110 if (!read_extension(&e_ext, e_ext.number))
2112 /* extension doesn't exist */
2113 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2114 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2115 new_state(EPOINT_STATE_OUT_DISCONNECT);
2116 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2120 /* put prefix in front of e_cbdialing */
2121 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2122 SCPY(e_dialinginfo.id, buffer);
2123 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2124 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2126 /* use caller id (or if exist: id_next_call) for this call */
2127 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2128 SCPY(e_callerinfo.extension, e_ext.number);
2129 if (e_ext.id_next_call_present >= 0)
2131 SCPY(e_callerinfo.id, e_ext.id_next_call);
2132 e_callerinfo.present = e_ext.id_next_call_present;
2133 e_callerinfo.ntype = e_ext.id_next_call_type;
2134 e_ext.id_next_call_present = -1;
2135 /* extension is written */
2136 write_extension(&e_ext, e_ext.number);
2139 SCPY(e_callerinfo.id, e_ext.callerid);
2140 e_callerinfo.present = e_ext.callerid_present;
2141 e_callerinfo.ntype = e_ext.callerid_type;
2144 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2147 /* check if caller id is NOT authenticated */
2148 if (!parse_callbackauth(e_ext.number, &e_callbackinfo))
2150 /* make call state to enter password */
2151 new_state(EPOINT_STATE_IN_OVERLAP);
2152 e_action = &action_password_write;
2153 e_match_timeout = 0;
2154 e_match_to_action = NULL;
2155 e_dialinginfo.id[0] = '\0';
2156 e_extdialing = strchr(e_dialinginfo.id, '\0');
2157 e_password_timeout = now+20;
2161 /* incoming call (callback) */
2162 e_ruleset = ruleset_main;
2164 e_rule = e_ruleset->rule_first;
2166 e_extdialing = e_dialinginfo.id;
2167 if (e_dialinginfo.id[0])
2169 set_tone(portlist, "dialing");
2173 set_tone(portlist, "dialpbx");
2176 } else /* testcall */
2178 set_tone(portlist, "hold");
2181 /* start recording if enabled, not when answering machine answers */
2182 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))
2184 /* check if we are a terminal */
2185 if (e_ext.number[0] == '\0')
2186 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2189 port = find_port_id(portlist->port_id);
2191 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2196 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2197 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2199 struct message *message;
2201 unsigned long port_id = portlist->port_id;
2205 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2207 /* signal to call tool */
2208 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2210 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2211 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE)// || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2213 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2218 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);
2219 collect_cause(&e_multipoint_cause, &e_multipoint_location, param->disconnectinfo.cause, param->disconnectinfo.location);
2220 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2222 /* check if we have more than one portlist relation and we just ignore the disconnect */
2223 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next)
2225 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2226 portlist = ea_endpoint->ep_portlist;
2229 if (portlist->port_id == port_id)
2231 portlist = portlist->next;
2234 FATAL("EPOINT(%d) no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2235 if (message_type != MESSAGE_RELEASE)
2237 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2238 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2239 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2240 message_put(message);
2241 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2243 ea_endpoint->free_portlist(portlist);
2244 return; /* one relation removed */
2246 if (e_state == EPOINT_STATE_CONNECT)
2248 /* use cause from port after connect */
2249 cause = param->disconnectinfo.cause;
2250 location = param->disconnectinfo.location;
2253 /* use multipoint cause if no connect yet */
2254 if (e_multipoint_cause)
2256 cause = e_multipoint_cause;
2257 location = e_multipoint_location;
2260 cause = CAUSE_NOUSER;
2261 location = LOCATION_PRIVATE_LOCAL;
2265 e_cfnr_call = e_cfnr_release = 0;
2267 /* process hangup */
2268 process_hangup(e_join_cause, e_join_location);
2269 e_multipoint_cause = 0;
2270 e_multipoint_location = 0;
2272 if (message_type == MESSAGE_DISCONNECT)
2274 /* tone to disconnected end */
2275 SPRINT(buffer, "cause_%02x", cause);
2276 if (ea_endpoint->ep_portlist)
2277 set_tone(ea_endpoint->ep_portlist, buffer);
2279 new_state(EPOINT_STATE_IN_DISCONNECT);
2282 if (ea_endpoint->ep_join_id)
2284 int haspatterns = 0;
2285 /* check if pattern is available */
2286 if (ea_endpoint->ep_portlist)
2287 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2288 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
2289 && message_type != MESSAGE_RELEASE) // if we release, we are done
2293 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2294 /* indicate patterns */
2295 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_PATTERN);
2296 message_put(message);
2297 /* connect audio, if not already */
2298 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2299 message->param.audiopath = CHANNEL_STATE_CONNECT;
2300 message_put(message);
2301 /* send disconnect */
2302 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, message_type);
2303 memcpy(&message->param, param, sizeof(union parameter));
2304 message_put(message);
2305 /* disable encryption if disconnected */
2306 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2308 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2312 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2315 if (message_type == MESSAGE_RELEASE)
2316 ea_endpoint->free_portlist(portlist);
2317 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */
2318 return; /* must exit here */
2321 /* port MESSAGE_TIMEOUT */
2322 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2326 trace_header("TIMEOUT", DIRECTION_IN);
2327 message_type = MESSAGE_DISCONNECT;
2328 switch (param->state)
2330 case PORT_STATE_OUT_SETUP:
2331 case PORT_STATE_OUT_OVERLAP:
2332 add_trace("state", NULL, "outgoing setup/dialing");
2334 /* no user responding */
2335 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2336 return; /* must exit here */
2338 case PORT_STATE_IN_SETUP:
2339 case PORT_STATE_IN_OVERLAP:
2340 add_trace("state", NULL, "incoming setup/dialing");
2341 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2342 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2345 case PORT_STATE_OUT_PROCEEDING:
2346 add_trace("state", NULL, "outgoing proceeding");
2348 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2349 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2350 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2351 return; /* must exit here */
2353 case PORT_STATE_IN_PROCEEDING:
2354 add_trace("state", NULL, "incoming proceeding");
2355 param->disconnectinfo.cause = CAUSE_NOUSER;
2356 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2359 case PORT_STATE_OUT_ALERTING:
2360 add_trace("state", NULL, "outgoing alerting");
2362 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2363 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2364 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2365 return; /* must exit here */
2367 case PORT_STATE_CONNECT:
2368 add_trace("state", NULL, "connect");
2370 param->disconnectinfo.cause = CAUSE_NORMAL; /* normal */
2371 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2372 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2373 return; /* must exit here */
2375 case PORT_STATE_IN_ALERTING:
2376 add_trace("state", NULL, "incoming alerting");
2377 param->disconnectinfo.cause = CAUSE_NOANSWER;
2378 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2381 case PORT_STATE_IN_DISCONNECT:
2382 case PORT_STATE_OUT_DISCONNECT:
2383 add_trace("state", NULL, "disconnect");
2385 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2386 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2387 return; /* must exit here */
2390 param->disconnectinfo.cause = 31; /* normal unspecified */
2391 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2394 /* release call, disconnect isdn */
2396 new_state(EPOINT_STATE_OUT_DISCONNECT);
2397 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2398 SCPY(e_tone, cause);
2401 set_tone(portlist, cause);
2402 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2403 portlist = portlist->next;
2405 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
2408 /* port MESSAGE_NOTIFY */
2409 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2411 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2413 struct message *message;
2417 /* signal to call tool */
2418 admin_call_response(e_adminid, ADMIN_CALL_NOTIFY, numberrize_callerinfo(param->notifyinfo.id,param->notifyinfo.ntype), 0, 0, param->notifyinfo.notify);
2419 if (param->notifyinfo.notify)
2421 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2424 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2425 if (param->notifyinfo.local) switch(param->notifyinfo.notify)
2427 case INFO_NOTIFY_REMOTE_HOLD:
2428 case INFO_NOTIFY_USER_SUSPENDED:
2429 /* tell call about it */
2430 if (ea_endpoint->ep_join_id)
2432 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2433 message->param.audiopath = CHANNEL_STATE_HOLD;
2434 message_put(message);
2438 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2439 case INFO_NOTIFY_USER_RESUMED:
2440 /* set volume of rx and tx */
2441 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2442 if (e_ext.tx_gain!=0 || e_ext.rx_gain!=0)
2445 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2446 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2447 message->param.mISDNsignal.rx_gain = e_ext.tx_gain;
2448 message->param.mISDNsignal.tx_gain = e_ext.rx_gain;
2449 message_put(message);
2451 /* set current tone */
2453 set_tone(portlist, e_tone);
2454 /* tell call about it */
2455 if (ea_endpoint->ep_join_id)
2457 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2458 message->param.audiopath = CHANNEL_STATE_CONNECT;
2459 message_put(message);
2464 /* get name of notify */
2465 switch(param->notifyinfo.notify)
2471 logtext = "USER_SUSPENDED";
2474 logtext = "BEARER_SERVICE_CHANGED";
2477 logtext = "USER_RESUMED";
2480 logtext = "CONFERENCE_ESTABLISHED";
2483 logtext = "CONFERENCE_DISCONNECTED";
2486 logtext = "OTHER_PARTY_ADDED";
2489 logtext = "ISOLATED";
2492 logtext = "REATTACHED";
2495 logtext = "OTHER_PARTY_ISOLATED";
2498 logtext = "OTHER_PARTY_REATTACHED";
2501 logtext = "OTHER_PARTY_SPLIT";
2504 logtext = "OTHER_PARTY_DISCONNECTED";
2507 logtext = "CONFERENCE_FLOATING";
2510 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2513 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2516 logtext = "CALL_IS_A_WAITING_CALL";
2519 logtext = "DIVERSION_ACTIVATED";
2522 logtext = "RESERVED_CT_1";
2525 logtext = "RESERVED_CT_2";
2528 logtext = "REVERSE_CHARGING";
2531 logtext = "REMOTE_HOLD";
2534 logtext = "REMOTE_RETRIEVAL";
2537 logtext = "CALL_IS_DIVERTING";
2540 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2545 /* notify call if available */
2546 if (ea_endpoint->ep_join_id)
2548 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_NOTIFY);
2549 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2550 message_put(message);
2555 /* port MESSAGE_FACILITY */
2556 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2558 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2560 struct message *message;
2562 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_FACILITY);
2563 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2564 message_put(message);
2567 /* port MESSAGE_SUSPEND */
2568 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2569 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2571 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2573 /* epoint is now parked */
2574 ea_endpoint->ep_park = 1;
2575 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2576 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2578 /* remove port relation */
2579 ea_endpoint->free_portlist(portlist);
2582 /* port MESSAGE_RESUME */
2583 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2584 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2586 logmessage(message_type, param, portlist->port_id, DIRECTION_IN);
2588 /* epoint is now resumed */
2589 ea_endpoint->ep_park = 0;
2594 /* port sends message to the endpoint
2596 void EndpointAppPBX::ea_message_port(unsigned long port_id, int message_type, union parameter *param)
2598 struct port_list *portlist;
2599 struct message *message;
2601 portlist = ea_endpoint->ep_portlist;
2604 if (port_id == portlist->port_id)
2606 portlist = portlist->next;
2610 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);
2614 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2615 switch(message_type)
2617 case MESSAGE_DATA: /* data from port */
2618 /* check if there is a call */
2619 if (!ea_endpoint->ep_join_id)
2621 /* continue if only one portlist */
2622 if (ea_endpoint->ep_portlist->next != NULL)
2624 /* forward message */
2625 message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2628 case MESSAGE_TONE_EOF: /* tone is end of file */
2629 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2632 if (e_action->index == ACTION_VBOX_PLAY)
2636 if (e_action->index == ACTION_EFI)
2643 case MESSAGE_TONE_COUNTER: /* counter info received */
2644 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);
2646 if (e_action->index == ACTION_VBOX_PLAY)
2648 e_vbox_counter = param->counter.current;
2649 if (param->counter.max >= 0)
2650 e_vbox_counter_max = param->counter.max;
2654 /* PORT sends SETUP message */
2656 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);
2657 if (e_state!=EPOINT_STATE_IDLE)
2659 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2662 port_setup(portlist, message_type, param);
2665 /* PORT sends INFORMATION message */
2666 case MESSAGE_INFORMATION: /* additional digits received */
2667 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);
2668 port_information(portlist, message_type, param);
2671 /* PORT sends FACILITY message */
2672 case MESSAGE_FACILITY:
2673 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2674 port_facility(portlist, message_type, param);
2677 /* PORT sends DTMF message */
2678 case MESSAGE_DTMF: /* dtmf digits received */
2679 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);
2680 port_dtmf(portlist, message_type, param);
2683 /* PORT sends CRYPT message */
2684 case MESSAGE_CRYPT: /* crypt response received */
2685 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2686 port_crypt(portlist, message_type, param);
2689 /* PORT sends MORE message */
2690 case MESSAGE_OVERLAP:
2691 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);
2692 if (e_state != EPOINT_STATE_OUT_SETUP)
2694 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);
2697 port_overlap(portlist, message_type, param);
2700 /* PORT sends PROCEEDING message */
2701 case MESSAGE_PROCEEDING: /* port is proceeding */
2702 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);
2703 if (e_state!=EPOINT_STATE_OUT_SETUP
2704 && e_state!=EPOINT_STATE_OUT_OVERLAP)
2706 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);
2709 port_proceeding(portlist, message_type, param);
2712 /* PORT sends ALERTING message */
2713 case MESSAGE_ALERTING:
2714 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);
2715 if (e_state!=EPOINT_STATE_OUT_SETUP
2716 && e_state!=EPOINT_STATE_OUT_OVERLAP
2717 && e_state!=EPOINT_STATE_OUT_PROCEEDING)
2719 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);
2722 port_alerting(portlist, message_type, param);
2725 /* PORT sends CONNECT message */
2726 case MESSAGE_CONNECT:
2727 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);
2728 if (e_state!=EPOINT_STATE_OUT_SETUP
2729 && e_state!=EPOINT_STATE_OUT_OVERLAP
2730 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2731 && e_state!=EPOINT_STATE_OUT_ALERTING)
2733 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2736 port_connect(portlist, message_type, param);
2739 /* PORT sends DISCONNECT message */
2740 case MESSAGE_DISCONNECT: /* port is disconnected */
2741 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);
2742 port_disconnect_release(portlist, message_type, param);
2745 /* PORT sends a RELEASE message */
2746 case MESSAGE_RELEASE: /* port releases */
2747 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);
2748 /* portlist is release at port_disconnect_release, thanx Paul */
2749 port_disconnect_release(portlist, message_type, param);
2752 /* PORT sends a TIMEOUT message */
2753 case MESSAGE_TIMEOUT:
2754 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);
2755 port_timeout(portlist, message_type, param);
2756 break; /* release */
2758 /* PORT sends a NOTIFY message */
2759 case MESSAGE_NOTIFY:
2760 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);
2761 port_notify(portlist, message_type, param);
2764 /* PORT sends a SUSPEND message */
2765 case MESSAGE_SUSPEND:
2766 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);
2767 port_suspend(portlist, message_type, param);
2768 break; /* suspend */
2770 /* PORT sends a RESUME message */
2771 case MESSAGE_RESUME:
2772 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);
2773 port_resume(portlist, message_type, param);
2777 /* port assigns bchannel */
2778 case MESSAGE_BCHANNEL: /* bchannel assignment messafe */
2779 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);
2780 /* only one port is expected to be connected to bchannel */
2781 message = message_forward(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, param);
2782 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_IN);
2788 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);
2791 /* Note: this endpoint may be destroyed, so we MUST return */
2795 /* messages from join
2797 /* join MESSAGE_CRYPT */
2798 void EndpointAppPBX::join_crypt(struct port_list *portlist, int message_type, union parameter *param)
2800 switch(param->crypt.type)
2802 /* message from remote port to "crypt manager" */
2803 case CU_ACTK_REQ: /* activate key-exchange */
2804 case CU_ACTS_REQ: /* activate shared key */
2805 case CU_DACT_REQ: /* deactivate */
2806 case CU_INFO_REQ: /* request last info message */
2807 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2810 /* message from "crypt manager" to user */
2811 case CU_ACTK_CONF: /* key-echange done */
2812 case CU_ACTS_CONF: /* shared key done */
2813 case CU_DACT_CONF: /* deactivated */
2814 case CU_DACT_IND: /* deactivated */
2815 case CU_ERROR_IND: /* receive error message */
2816 case CU_INFO_IND: /* receive info message */
2817 case CU_INFO_CONF: /* receive info message */
2818 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2822 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);
2826 /* join MESSAGE_INFORMATION */
2827 void EndpointAppPBX::join_information(struct port_list *portlist, int message_type, union parameter *param)
2829 struct message *message;
2835 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2836 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
2837 message_put(message);
2838 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2839 portlist = portlist->next;
2843 /* join MESSAGE_FACILITY */
2844 void EndpointAppPBX::join_facility(struct port_list *portlist, int message_type, union parameter *param)
2846 struct message *message;
2848 if (!e_ext.facility && e_ext.number[0])
2855 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
2856 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2857 message_put(message);
2858 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2859 portlist = portlist->next;
2863 /* join MESSAGE_MORE */
2864 void EndpointAppPBX::join_overlap(struct port_list *portlist, int message_type, union parameter *param)
2866 struct message *message;
2868 new_state(EPOINT_STATE_IN_OVERLAP);
2871 if (e_join_pattern && e_ext.own_setup)
2873 /* disconnect audio */
2874 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2875 message->param.audiopath = CHANNEL_STATE_HOLD;
2876 message_put(message);
2878 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
2880 if (e_dialinginfo.id[0])
2881 set_tone(portlist, "dialing");
2883 set_tone(portlist, "dialtone");
2886 if (e_ext.number[0])
2887 set_tone(portlist, "dialpbx");
2889 set_tone(portlist, "dialtone");
2892 /* join MESSAGE_PROCEEDING */
2893 void EndpointAppPBX::join_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2895 struct message *message;
2897 new_state(EPOINT_STATE_IN_PROCEEDING);
2899 /* own proceeding tone */
2902 /* connect / disconnect audio */
2903 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2904 if (e_ext.own_proceeding)
2905 message->param.audiopath = CHANNEL_STATE_HOLD;
2907 message->param.audiopath = CHANNEL_STATE_CONNECT;
2908 message_put(message);
2910 // UCPY(e_join_tone, "proceeding");
2913 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
2914 message_put(message);
2915 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2917 set_tone(portlist, "proceeding");
2920 /* join MESSAGE_ALERTING */
2921 void EndpointAppPBX::join_alerting(struct port_list *portlist, int message_type, union parameter *param)
2923 struct message *message;
2925 new_state(EPOINT_STATE_IN_ALERTING);
2927 /* own alerting tone */
2930 /* connect / disconnect audio */
2931 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
2932 if (e_ext.own_alerting)
2933 message->param.audiopath = CHANNEL_STATE_HOLD;
2935 message->param.audiopath = CHANNEL_STATE_CONNECT;
2936 message_put(message);
2940 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
2941 message_put(message);
2942 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2944 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
2946 set_tone(portlist, "ringing");
2949 if (e_ext.number[0])
2950 set_tone(portlist, "ringpbx");
2952 set_tone(portlist, "ringing");
2955 /* join MESSAGE_CONNECT */
2956 void EndpointAppPBX::join_connect(struct port_list *portlist, int message_type, union parameter *param)
2958 struct message *message;
2960 new_state(EPOINT_STATE_CONNECT);
2961 // UCPY(e_join_tone, "");
2962 if (e_ext.number[0])
2963 e_dtmf = 1; /* allow dtmf */
2965 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
2968 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
2969 memcpy(&message->param, param, sizeof(union parameter));
2971 /* screen clip if prefix is required */
2972 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0])
2974 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
2975 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype));
2976 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2979 /* use internal caller id */
2980 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore))
2982 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
2983 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2986 /* handle restricted caller ids */
2987 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);
2988 /* display callerid if desired for extension */
2989 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));
2991 /* use conp, if enabld */
2992 // if (!e_ext.centrex)
2993 // message->param.connectinfo.name[0] = '\0';
2996 message_put(message);
2997 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
2999 set_tone(portlist, NULL);
3001 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3002 message->param.audiopath = CHANNEL_STATE_CONNECT;
3003 message_put(message);
3007 /* join MESSAGE_DISCONNECT MESSAGE_RELEASE */
3008 void EndpointAppPBX::join_disconnect_release(int message_type, union parameter *param)
3011 struct message *message;
3012 struct port_list *portlist = NULL;
3015 /* be sure that we are active */
3017 e_tx_state = NOTIFY_STATE_ACTIVE;
3019 /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
3020 if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1))
3022 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
3024 /* set time for power dialing */
3025 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
3028 /* set redial tone */
3029 if (ea_endpoint->ep_portlist)
3033 set_tone(ea_endpoint->ep_portlist, "redial");
3034 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);
3035 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3036 if (e_state==EPOINT_STATE_IN_OVERLAP)
3038 new_state(EPOINT_STATE_IN_PROCEEDING);
3039 if (ea_endpoint->ep_portlist)
3041 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3042 message_put(message);
3043 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3045 /* caused the error, that the first knock sound was not there */
3046 /* set_tone(portlist, "proceeding"); */
3048 /* send display of powerdialing */
3049 if (e_ext.display_dialing)
3051 portlist = ea_endpoint->ep_portlist;
3054 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3056 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3058 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3059 message_put(message);
3060 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3061 portlist = portlist->next;
3070 if ((e_state!=EPOINT_STATE_CONNECT
3071 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3072 && e_state!=EPOINT_STATE_IN_OVERLAP
3073 && e_state!=EPOINT_STATE_IN_PROCEEDING
3074 && e_state!=EPOINT_STATE_IN_ALERTING)
3075 || !ea_endpoint->ep_portlist) /* or no port */
3077 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3078 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, join, port */
3079 return; /* must exit here */
3084 e_join_cause = param->disconnectinfo.cause;
3085 e_join_location = param->disconnectinfo.location;
3088 /* on release we need the audio again! */
3089 if (message_type == MESSAGE_RELEASE)
3092 ea_endpoint->ep_join_id = 0;
3094 /* disconnect and select tone */
3095 new_state(EPOINT_STATE_OUT_DISCONNECT);
3096 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3097 /* if own_cause, we must release the join */
3098 if (e_ext.own_cause /* own cause */
3099 || !e_join_pattern) /* no patterns */
3101 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);
3102 if (message_type != MESSAGE_RELEASE)
3103 release(RELEASE_JOIN, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, join, port */
3105 } else /* else we enable audio */
3107 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3108 message->param.audiopath = CHANNEL_STATE_CONNECT;
3109 message_put(message);
3111 /* send disconnect message */
3112 SCPY(e_tone, cause);
3113 portlist = ea_endpoint->ep_portlist;
3116 set_tone(portlist, cause);
3117 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3118 portlist = portlist->next;
3122 /* join MESSAGE_SETUP */
3123 void EndpointAppPBX::join_setup(struct port_list *portlist, int message_type, union parameter *param)
3125 struct message *message;
3126 // struct interface *interface;
3128 /* if we already in setup state, we just update the dialing with new digits */
3129 if (e_state == EPOINT_STATE_OUT_SETUP
3130 || e_state == EPOINT_STATE_OUT_OVERLAP)
3132 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3133 /* if digits changed, what we have already dialed */
3134 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id)))
3136 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);
3137 /* release all ports */
3138 while((portlist = ea_endpoint->ep_portlist))
3140 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3141 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3142 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3143 message_put(message);
3144 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3145 ea_endpoint->free_portlist(portlist);
3148 /* disconnect audio */
3149 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3150 message->param.audiopath = CHANNEL_STATE_HOLD;
3151 message_put(message);
3153 /* get dialing info */
3154 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3155 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3156 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3157 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3158 new_state(EPOINT_STATE_OUT_OVERLAP);
3161 e_redial = now_d + 1; /* set redial one second in the future */
3164 /* if we have a pending redial, so we just adjust the dialing number */
3167 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);
3168 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3171 if (!ea_endpoint->ep_portlist)
3173 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3175 if (ea_endpoint->ep_portlist->next)
3177 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3179 if (e_state == EPOINT_STATE_OUT_SETUP)
3182 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);
3183 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3187 /* get what we have not dialed yet */
3188 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));
3189 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3190 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3191 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3192 message_put(message);
3193 logmessage(message->type, &message->param, ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
3195 /* always store what we have dialed or queued */
3196 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3200 if (e_state != EPOINT_STATE_IDLE)
3202 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3205 /* if an internal extension is dialed, copy that number */
3206 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3207 SCPY(e_ext.number, param->setup.dialinginfo.id);
3208 /* if an internal extension is dialed, get extension's info about caller */
3209 if (e_ext.number[0])
3211 if (!read_extension(&e_ext, e_ext.number))
3213 e_ext.number[0] = '\0';
3214 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3218 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3219 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3220 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3221 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3223 /* process (voice over) data calls */
3224 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO)
3226 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3227 memset(&e_capainfo, 0, sizeof(e_capainfo));
3228 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3229 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3230 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3233 new_state(EPOINT_STATE_OUT_SETUP);
3234 /* call special setup routine */
3238 /* join MESSAGE_mISDNSIGNAL */
3239 void EndpointAppPBX::join_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3241 struct message *message;
3245 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3246 memcpy(&message->param, param, sizeof(union parameter));
3247 message_put(message);
3248 portlist = portlist->next;
3252 /* join MESSAGE_NOTIFY */
3253 void EndpointAppPBX::join_notify(struct port_list *portlist, int message_type, union parameter *param)
3255 struct message *message;
3258 if (param->notifyinfo.notify)
3260 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3261 // /* if notification was generated locally, we turn hold music on/off */
3262 // if (param->notifyinfo.local)
3263 // 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)
3268 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND)
3270 if (!strcmp(e_tone, "hold")) // don't interrupt other tones
3274 set_tone(portlist, "");
3275 portlist = portlist->next;
3278 portlist = ea_endpoint->ep_portlist;
3283 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND)
3287 set_tone(portlist, "hold");
3288 portlist = portlist->next;
3290 portlist = ea_endpoint->ep_portlist;
3295 /* save new state */
3296 e_tx_state = new_state;
3299 /* notify port(s) about it */
3302 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3303 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3304 /* handle restricted caller ids */
3305 apply_callerid_restriction(&e_ext, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3306 /* display callerid if desired for extension */
3307 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));
3308 message_put(message);
3309 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3310 portlist = portlist->next;
3314 /* JOIN sends messages to the endpoint
3316 void EndpointAppPBX::ea_message_join(unsigned long join_id, int message_type, union parameter *param)
3318 struct port_list *portlist;
3319 struct message *message;
3323 PERROR("EPOINT(%d) error: JOIN == NULL.\n", ea_endpoint->ep_serial);
3327 portlist = ea_endpoint->ep_portlist;
3329 /* send MESSAGE_DATA to port */
3330 if (message_type == MESSAGE_DATA)
3332 if (join_id == ea_endpoint->ep_join_id) // still linked with JOIN
3334 /* skip if no port relation */
3337 /* skip if more than one port relation */
3340 /* forward audio data to port */
3341 message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3346 // 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);
3347 switch(message_type)
3349 /* JOIN SENDS TONE message */
3351 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);
3352 set_tone(portlist, param->tone.name);
3355 /* JOIN SENDS CRYPT message */
3357 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);
3358 join_crypt(portlist, message_type, param);
3361 /* JOIN sends INFORMATION message */
3362 case MESSAGE_INFORMATION:
3363 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);
3364 join_information(portlist, message_type, param);
3367 /* JOIN sends FACILITY message */
3368 case MESSAGE_FACILITY:
3369 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);
3370 join_facility(portlist, message_type, param);
3373 /* JOIN sends OVERLAP message */
3374 case MESSAGE_OVERLAP:
3375 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received 'more info available'\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
3376 if (e_state!=EPOINT_STATE_IN_SETUP
3377 && e_state!=EPOINT_STATE_IN_OVERLAP)
3379 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3382 join_overlap(portlist, message_type, param);
3385 /* JOIN sends PROCEEDING message */
3386 case MESSAGE_PROCEEDING:
3387 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);
3388 if(e_state!=EPOINT_STATE_IN_OVERLAP)
3390 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3393 join_proceeding(portlist, message_type, param);
3396 /* JOIN sends ALERTING message */
3397 case MESSAGE_ALERTING:
3398 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);
3399 if (e_state!=EPOINT_STATE_IN_OVERLAP
3400 && e_state!=EPOINT_STATE_IN_PROCEEDING)
3402 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3405 join_alerting(portlist, message_type, param);
3408 /* JOIN sends CONNECT message */
3409 case MESSAGE_CONNECT:
3410 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);
3411 if (e_state!=EPOINT_STATE_IN_OVERLAP
3412 && e_state!=EPOINT_STATE_IN_PROCEEDING
3413 && e_state!=EPOINT_STATE_IN_ALERTING)
3415 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3418 join_connect(portlist, message_type, param);
3421 /* JOIN sends DISCONNECT/RELEASE message */
3422 case MESSAGE_DISCONNECT: /* JOIN disconnect */
3423 case MESSAGE_RELEASE: /* JOIN releases */
3424 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);
3425 join_disconnect_release(message_type, param);
3428 /* JOIN sends SETUP message */
3430 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);
3431 join_setup(portlist, message_type, param);
3434 /* JOIN sends special mISDNSIGNAL message */
3435 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3436 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);
3437 join_mISDNsignal(portlist, message_type, param);
3441 /* JOIN requests bchannel */
3442 case MESSAGE_BCHANNEL: /* indicates the need of own bchannel access */
3443 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) epoint with terminal '%s' (caller id '%s') received bchannel assignment %d from join.\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id, param->bchannel.type);
3444 /* only one port is expected to be connected to bchannel */
3451 set_tone(portlist, NULL);
3452 message = message_forward(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, param);
3453 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
3457 /* JOIN has pattern available */
3458 case MESSAGE_PATTERN: /* indicating pattern available */
3459 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);
3460 if (!e_join_pattern)
3462 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3467 set_tone(portlist, NULL);
3468 portlist = portlist->next;
3470 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3471 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3472 message->param.audiopath = CHANNEL_STATE_CONNECT;
3473 message_put(message);
3474 // /* tell remote epoint to connect audio also, because we like to hear the patterns */
3475 // message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_REMOTE_AUDIO);
3476 // message->param.audiopath = CHANNEL_STATE_CONNECT;
3477 // message_put(message);
3478 // patterns are available, remote already connected audio
3482 /* JOIN has no pattern available */
3483 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3484 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);
3487 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3489 /* disconnect our audio tx and rx */
3490 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3491 message->param.audiopath = CHANNEL_STATE_HOLD;
3492 message_put(message);
3497 /* JOIN (dunno at the moment) */
3498 case MESSAGE_REMOTE_AUDIO:
3499 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);
3500 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3501 message->param.audiopath = param->channel;
3502 message_put(message);
3506 /* JOIN sends a notify message */
3507 case MESSAGE_NOTIFY:
3508 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);
3509 join_notify(portlist, message_type, param);
3513 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);
3518 /* pick_join will connect the first incoming call found. the endpoint
3519 * will receivce a MESSAGE_CONNECT.
3521 int match_list(char *list, char *item)
3523 char *end, *next = NULL;
3525 /* no list make matching */
3531 /* eliminate white spaces */
3532 while (*list <= ' ')
3539 /* if end of list is reached, we return */
3540 if (list[0] == '\0')
3542 /* if we have more than one entry (left) */
3543 if ((end = strchr(list, ',')))
3546 next = end = strchr(list, '\0');
3547 while (*(end-1) <= ' ')
3549 /* if string part matches item */
3550 if (!strncmp(list, item, end-list))
3556 void EndpointAppPBX::pick_join(char *extensions)
3558 struct message *message;
3559 struct port_list *portlist;
3561 class EndpointAppPBX *eapp, *found;
3563 class JoinPBX *joinpbx;
3564 struct join_relation *relation;
3567 /* find an endpoint that is ringing internally or vbox with higher priority */
3570 eapp = apppbx_first;
3573 if (eapp!=this && ea_endpoint->ep_portlist)
3575 portlist = eapp->ea_endpoint->ep_portlist;
3578 if ((port = find_port_id(portlist->port_id)))
3580 if (port->p_type == PORT_TYPE_VBOX_OUT)
3582 if (match_list(extensions, eapp->e_ext.number))
3589 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT)
3590 && port->p_state==PORT_STATE_OUT_ALERTING)
3591 if (match_list(extensions, eapp->e_ext.number))
3596 portlist = portlist->next;
3604 /* if no endpoint found */
3607 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);
3609 set_tone(ea_endpoint->ep_portlist, "cause_10");
3610 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3611 new_state(EPOINT_STATE_OUT_DISCONNECT);
3616 if (ea_endpoint->ep_join_id)
3618 PERROR("EPOINT(%d) we already have a join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3621 if (!eapp->ea_endpoint->ep_join_id)
3623 PERROR("EPOINT(%d) ringing endpoint has no join.\n", ea_endpoint->ep_serial);
3626 join = find_join_id(eapp->ea_endpoint->ep_join_id);
3629 PERROR("EPOINT(%d) ringing endpoint's join not found.\n", ea_endpoint->ep_serial);
3632 if (join->j_type != JOIN_TYPE_PBX)
3634 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's join is not a PBX join, so we must reject.\n", ea_endpoint->ep_serial);
3637 joinpbx = (class JoinPBX *)join;
3638 relation = joinpbx->j_relation;
3641 PERROR("EPOINT(%d) ringing endpoint's join has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3644 while (relation->epoint_id != eapp->ea_endpoint->ep_serial)
3646 relation = relation->next;
3649 PERROR("EPOINT(%d) ringing endpoint's join has no relation to that join. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3654 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3656 if (options.deb & DEBUG_EPOINT)
3658 class Join *debug_c = join_first;
3659 class Endpoint *debug_e = epoint_first;
3660 class Port *debug_p = port_first;
3662 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(before)");
3664 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3667 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3668 debug_c = debug_c->next;
3670 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3673 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3674 debug_e = debug_e->next;
3676 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3679 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3680 debug_p = debug_p->next;
3685 ea_endpoint->ep_join_id = eapp->ea_endpoint->ep_join_id; /* we get the join */
3686 relation->epoint_id = ea_endpoint->ep_serial; /* the join gets us */
3687 eapp->ea_endpoint->ep_join_id = 0; /* the ringing endpoint will get disconnected */
3689 /* connnecting our endpoint */
3690 new_state(EPOINT_STATE_CONNECT);
3692 set_tone(ea_endpoint->ep_portlist, NULL);
3694 /* now we send a release to the ringing endpoint */
3695 message = message_create(ea_endpoint->ep_join_id, eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3696 message->param.disconnectinfo.cause = CAUSE_NONSELECTED; /* non selected user clearing */
3697 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3698 message_put(message);
3700 /* we send a connect to the join with our caller id */
3701 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_CONNECT);
3702 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3703 message->param.connectinfo.present = e_callerinfo.present;
3704 message->param.connectinfo.screen = e_callerinfo.screen;
3705 message->param.connectinfo.itype = e_callerinfo.itype;
3706 message->param.connectinfo.ntype = e_callerinfo.ntype;
3707 message_put(message);
3709 /* we send a connect to our port with the remote callerid */
3710 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3711 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3712 message->param.connectinfo.present = eapp->e_callerinfo.present;
3713 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3714 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3715 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3716 /* handle restricted caller ids */
3717 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);
3718 /* display callerid if desired for extension */
3719 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));
3720 message_put(message);
3722 /* we send a connect to the audio path (not for vbox) */
3723 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_join_id, EPOINT_TO_JOIN, MESSAGE_AUDIOPATH);
3724 message->param.audiopath = CHANNEL_STATE_CONNECT;
3725 message_put(message);
3727 /* beeing paranoid, we make call update */
3728 joinpbx->j_updatebridge = 1;
3730 if (options.deb & DEBUG_EPOINT)
3732 class Join *debug_c = join_first;
3733 class Endpoint *debug_e = epoint_first;
3734 class Port *debug_p = port_first;
3736 joinpbx_debug(joinpbx, "EndpointAppPBX::pick_join(after)");
3738 PDEBUG(DEBUG_EPOINT, "showing all joins:\n");
3741 PDEBUG(DEBUG_EPOINT, "join=%ld\n", debug_c->j_serial);
3742 debug_c = debug_c->next;
3744 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3747 PDEBUG(DEBUG_EPOINT, "ep=%ld, join=%ld\n", debug_e->ep_serial, debug_e->ep_join_id);
3748 debug_e = debug_e->next;
3750 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3753 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3754 debug_p = debug_p->next;
3760 /* join calls (look for a join that is on hold (same isdn interface/terminal))
3762 void EndpointAppPBX::join_join(void)
3764 struct message *message;
3765 struct join_relation *our_relation, *other_relation;
3766 struct join_relation **our_relation_pointer, **other_relation_pointer;
3767 class Join *our_join, *other_join;
3768 class JoinPBX *our_joinpbx, *other_joinpbx;
3769 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3770 class Port *our_port, *other_port;
3771 class Pdss1 *our_pdss1, *other_pdss1;
3773 /* are we a candidate to join a join */
3774 our_join = find_join_id(ea_endpoint->ep_join_id);
3777 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3780 if (our_join->j_type != JOIN_TYPE_PBX)
3782 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: join is not a pbx join.\n", ea_endpoint->ep_serial);
3785 our_joinpbx = (class JoinPBX *)our_join;
3786 if (!ea_endpoint->ep_portlist)
3788 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3791 if (!e_ext.number[0])
3793 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3796 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3799 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3802 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
3804 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3807 our_pdss1 = (class Pdss1 *)our_port;
3809 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3810 other_eapp = apppbx_first;
3813 if (other_eapp == this)
3815 other_eapp = other_eapp->next;
3818 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);
3819 if (other_eapp->e_ext.number[0] /* has terminal */
3820 && other_eapp->ea_endpoint->ep_portlist /* has port */
3821 && other_eapp->ea_endpoint->ep_join_id) /* has join */
3823 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3824 if (other_port) /* port still exists */
3826 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3827 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) /* port is isdn nt-mode */
3829 other_pdss1 = (class Pdss1 *)other_port;
3830 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);
3831 if (other_pdss1->p_m_hold /* port is on hold */
3832 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3833 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3837 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3841 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3844 other_eapp = other_eapp->next;
3848 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn interface with port on hold.\n", ea_endpoint->ep_serial);
3851 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port on hold found.\n", ea_endpoint->ep_serial);
3853 /* if we have the same join */
3854 if (other_eapp->ea_endpoint->ep_join_id == ea_endpoint->ep_join_id)
3856 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we an the other have the same join.\n", ea_endpoint->ep_serial);
3859 other_join = find_join_id(other_eapp->ea_endpoint->ep_join_id);
3862 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join doesn't exist anymore.\n", ea_endpoint->ep_serial);
3865 if (other_join->j_type != JOIN_TYPE_PBX)
3867 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other join is not a pbx join.\n", ea_endpoint->ep_serial);
3870 other_joinpbx = (class JoinPBX *)other_join;
3871 if (our_joinpbx->j_partyline && other_joinpbx->j_partyline)
3873 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both joins are partylines.\n", ea_endpoint->ep_serial);
3877 /* remove relation to endpoint for join on hold */
3878 other_relation = other_joinpbx->j_relation;
3879 other_relation_pointer = &other_joinpbx->j_relation;
3880 while(other_relation)
3882 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial)
3884 /* detach other endpoint on hold */
3885 *other_relation_pointer = other_relation->next;
3886 FREE(other_relation, sizeof(struct join_relation));
3888 other_relation = *other_relation_pointer;
3889 other_eapp->ea_endpoint->ep_join_id = NULL;
3893 /* change join/hold pointer of endpoint to the new join */
3894 temp_epoint = find_epoint_id(other_relation->epoint_id);
3897 if (temp_epoint->ep_join_id == other_join->j_serial)
3898 temp_epoint->ep_join_id = our_join->j_serial;
3901 other_relation_pointer = &other_relation->next;
3902 other_relation = other_relation->next;
3904 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on join relinked (to our join).\n", ea_endpoint->ep_serial);
3906 /* join call relations */
3907 our_relation = our_joinpbx->j_relation;
3908 our_relation_pointer = &our_joinpbx->j_relation;
3911 our_relation_pointer = &our_relation->next;
3912 our_relation = our_relation->next;
3914 *our_relation_pointer = other_joinpbx->j_relation;
3915 other_joinpbx->j_relation = NULL;
3916 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
3918 /* release endpoint on hold */
3919 message = message_create(other_joinpbx->j_serial, other_eapp->ea_endpoint->ep_serial, JOIN_TO_EPOINT, MESSAGE_RELEASE);
3920 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
3921 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3922 message_put(message);
3924 /* if we are not a partyline, we get partyline state from other join */
3925 our_joinpbx->j_partyline += other_joinpbx->j_partyline;
3927 /* remove empty join */
3929 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-join completely removed!\n");
3931 /* mixer must update */
3932 our_joinpbx->j_updatebridge = 1; /* update mixer flag */
3934 /* we send a retrieve to that endpoint */
3935 // mixer will update the hold-state of the join and send it to the endpoints is changes
3939 /* check if we have an external call
3940 * this is used to check for encryption ability
3942 int EndpointAppPBX::check_external(char **errstr, class Port **port)
3944 struct join_relation *relation;
3946 class JoinPBX *joinpbx;
3947 class Endpoint *epoint;
3949 /* some paranoia check */
3950 if (!ea_endpoint->ep_portlist)
3952 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
3953 *errstr = "No Call";
3956 if (!e_ext.number[0])
3958 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
3959 *errstr = "No Call";
3963 /* check if we have a join with 2 parties */
3964 join = find_join_id(ea_endpoint->ep_join_id);
3967 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no join.\n", ea_endpoint->ep_serial);
3968 *errstr = "No Call";
3971 if (join->j_type != JOIN_TYPE_PBX)
3973 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join is not a pbx join.\n", ea_endpoint->ep_serial);
3974 *errstr = "No PBX Call";
3977 joinpbx = (class JoinPBX *)join;
3978 relation = joinpbx->j_relation;
3981 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no relation.\n", ea_endpoint->ep_serial);
3982 *errstr = "No Call";
3985 if (!relation->next)
3987 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd relation.\n", ea_endpoint->ep_serial);
3988 *errstr = "No Call";
3991 if (relation->next->next)
3993 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has more than two relations.\n", ea_endpoint->ep_serial);
3994 *errstr = "Err: Conference";
3997 if (relation->epoint_id == ea_endpoint->ep_serial)
3999 relation = relation->next;
4000 if (relation->epoint_id == ea_endpoint->ep_serial)
4002 PERROR("EPOINT(%d) SOFTWARE ERROR: both join relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4003 *errstr = "Software Error";
4008 /* check remote port for external call */
4009 epoint = find_epoint_id(relation->epoint_id);
4012 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4013 *errstr = "No Call";
4016 if (!epoint->ep_portlist)
4018 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4019 *errstr = "No Call";
4022 *port = find_port_id(epoint->ep_portlist->port_id);
4025 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4026 *errstr = "No Call";
4029 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) /* port is not external isdn */
4031 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4032 *errstr = "No Ext Call";
4035 if ((*port)->p_state != PORT_STATE_CONNECT)
4037 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4038 *errstr = "No Ext Connect";
4044 void EndpointAppPBX::logmessage(int message_type, union parameter *param, unsigned long port_id, int dir)
4046 char *logtext = "unknown";
4049 switch(message_type)
4052 trace_header("SETUP", dir);
4053 if (dir == DIRECTION_OUT)
4054 add_trace("to", NULL, "CH(%lu)", port_id);
4055 if (dir == DIRECTION_IN)
4056 add_trace("from", NULL, "CH(%lu)", port_id);
4057 if (param->setup.callerinfo.extension[0])
4058 add_trace("extension", NULL, "%s", param->setup.callerinfo.extension);
4059 add_trace("caller id", "number", "%s", numberrize_callerinfo(param->setup.callerinfo.id, param->setup.callerinfo.ntype));
4060 switch(param->setup.callerinfo.present)
4062 case INFO_PRESENT_RESTRICTED:
4063 add_trace("caller id", "present", "restricted");
4065 case INFO_PRESENT_ALLOWED:
4066 add_trace("caller id", "present", "allowed");
4069 add_trace("caller id", "present", "not available");
4071 if (param->setup.redirinfo.id[0])
4073 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(param->setup.redirinfo.id, param->setup.redirinfo.ntype));
4074 switch(param->setup.redirinfo.present)
4076 case INFO_PRESENT_RESTRICTED:
4077 add_trace("redir'ing", "present", "restricted");
4079 case INFO_PRESENT_ALLOWED:
4080 add_trace("redir'ing", "present", "allowed");
4083 add_trace("redir'ing", "present", "not available");
4086 if (param->setup.dialinginfo.id[0])
4087 add_trace("dialing", NULL, "%s", param->setup.dialinginfo.id);
4091 case MESSAGE_OVERLAP:
4092 trace_header("SETUP ACKNOWLEDGE", dir);
4093 if (dir == DIRECTION_OUT)
4094 add_trace("to", NULL, "CH(%lu)", port_id);
4095 if (dir == DIRECTION_IN)
4096 add_trace("from", NULL, "CH(%lu)", port_id);
4100 case MESSAGE_PROCEEDING:
4101 trace_header("PROCEEDING", dir);
4102 if (dir == DIRECTION_OUT)
4103 add_trace("to", NULL, "CH(%lu)", port_id);
4104 if (dir == DIRECTION_IN)
4105 add_trace("from", NULL, "CH(%lu)", port_id);
4109 case MESSAGE_ALERTING:
4110 trace_header("ALERTING", dir);
4111 if (dir == DIRECTION_OUT)
4112 add_trace("to", NULL, "CH(%lu)", port_id);
4113 if (dir == DIRECTION_IN)
4114 add_trace("from", NULL, "CH(%lu)", port_id);
4118 case MESSAGE_CONNECT:
4119 trace_header("CONNECT", dir);
4120 if (dir == DIRECTION_OUT)
4121 add_trace("to", NULL, "CH(%lu)", port_id);
4122 if (dir == DIRECTION_IN)
4123 add_trace("from", NULL, "CH(%lu)", port_id);
4124 if (param->connectinfo.extension[0])
4125 add_trace("extension", NULL, "%s", param->connectinfo.extension);
4126 add_trace("connect id", "number", "%s", numberrize_callerinfo(param->connectinfo.id, param->connectinfo.ntype));
4127 switch(param->connectinfo.present)
4129 case INFO_PRESENT_RESTRICTED:
4130 add_trace("connect id", "present", "restricted");
4132 case INFO_PRESENT_ALLOWED:
4133 add_trace("connect id", "present", "allowed");
4136 add_trace("connect id", "present", "not available");
4141 case MESSAGE_DISCONNECT:
4142 case MESSAGE_RELEASE:
4143 if (message_type == MESSAGE_DISCONNECT)
4144 trace_header("DISCONNECT", dir);
4146 trace_header("RELEASE", dir);
4147 if (dir == DIRECTION_OUT)
4148 add_trace("to", NULL, "CH(%lu)", port_id);
4149 if (dir == DIRECTION_IN)
4150 add_trace("from", NULL, "CH(%lu)", port_id);
4151 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
4152 switch(param->disconnectinfo.location)
4155 add_trace("cause", "location", "0-User");
4157 case LOCATION_PRIVATE_LOCAL:
4158 add_trace("cause", "location", "1-Local-PBX");
4160 case LOCATION_PUBLIC_LOCAL:
4161 add_trace("cause", "location", "2-Local-Exchange");
4163 case LOCATION_TRANSIT:
4164 add_trace("cause", "location", "3-Transit");
4166 case LOCATION_PUBLIC_REMOTE:
4167 add_trace("cause", "location", "4-Remote-Exchange");
4169 case LOCATION_PRIVATE_REMOTE:
4170 add_trace("cause", "location", "5-Remote-PBX");
4172 case LOCATION_INTERNATIONAL:
4173 add_trace("cause", "location", "7-International-Exchange");
4175 case LOCATION_BEYOND:
4176 add_trace("cause", "location", "10-Beyond-Interworking");
4179 add_trace("cause", "location", "%d", param->disconnectinfo.location);
4184 case MESSAGE_NOTIFY:
4185 switch(param->notifyinfo.notify)
4191 logtext = "USER_SUSPENDED";
4194 logtext = "BEARER_SERVICE_CHANGED";
4197 logtext = "USER_RESUMED";
4200 logtext = "CONFERENCE_ESTABLISHED";
4203 logtext = "CONFERENCE_DISCONNECTED";
4206 logtext = "OTHER_PARTY_ADDED";
4209 logtext = "ISOLATED";
4212 logtext = "REATTACHED";
4215 logtext = "OTHER_PARTY_ISOLATED";
4218 logtext = "OTHER_PARTY_REATTACHED";
4221 logtext = "OTHER_PARTY_SPLIT";
4224 logtext = "OTHER_PARTY_DISCONNECTED";
4227 logtext = "CONFERENCE_FLOATING";
4230 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4233 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4236 logtext = "CALL_IS_A_WAITING_CALL";
4239 logtext = "DIVERSION_ACTIVATED";
4242 logtext = "RESERVED_CT_1";
4245 logtext = "RESERVED_CT_2";
4248 logtext = "REVERSE_CHARGING";
4251 logtext = "REMOTE_HOLD";
4254 logtext = "REMOTE_RETRIEVAL";
4257 logtext = "CALL_IS_DIVERTING";
4260 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
4264 trace_header("NOTIFY", dir);
4265 if (dir == DIRECTION_OUT)
4266 add_trace("to", NULL, "CH(%lu)", port_id);
4267 if (dir == DIRECTION_IN)
4268 add_trace("from", NULL, "CH(%lu)", port_id);
4269 if (param->notifyinfo.notify)
4270 add_trace("indicator", NULL, "%s", logtext);
4271 if (param->notifyinfo.id[0])
4273 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype));
4274 switch(param->notifyinfo.present)
4276 case INFO_PRESENT_RESTRICTED:
4277 add_trace("redir'on", "present", "restricted");
4279 case INFO_PRESENT_ALLOWED:
4280 add_trace("redir'on", "present", "allowed");
4283 add_trace("redir'on", "present", "not available");
4286 if (param->notifyinfo.display[0])
4287 add_trace("display", NULL, "%s", param->notifyinfo.display);
4291 case MESSAGE_INFORMATION:
4292 trace_header("INFORMATION", dir);
4293 if (dir == DIRECTION_OUT)
4294 add_trace("to", NULL, "CH(%lu)", port_id);
4295 if (dir == DIRECTION_IN)
4296 add_trace("from", NULL, "CH(%lu)", port_id);
4297 add_trace("dialing", NULL, "%s", param->information.id);
4301 case MESSAGE_FACILITY:
4302 trace_header("FACILITY", dir);
4303 if (dir == DIRECTION_OUT)
4304 add_trace("to", NULL, "CH(%lu)", port_id);
4305 if (dir == DIRECTION_IN)
4306 add_trace("from", NULL, "CH(%lu)", port_id);
4311 trace_header("TONE", dir);
4312 if (dir == DIRECTION_OUT)
4313 add_trace("to", NULL, "CH(%lu)", port_id);
4314 if (dir == DIRECTION_IN)
4315 add_trace("from", NULL, "CH(%lu)", port_id);
4316 if (param->tone.name[0])
4318 add_trace("directory", NULL, "%s", param->tone.dir[0]?param->tone.dir:"default");
4319 add_trace("name", NULL, "%s", param->tone.name);
4321 add_trace("off", NULL, NULL);
4325 case MESSAGE_SUSPEND:
4326 case MESSAGE_RESUME:
4327 if (message_type == MESSAGE_SUSPEND)
4328 trace_header("SUSPEND", dir);
4330 trace_header("RESUME", dir);
4331 if (dir == DIRECTION_OUT)
4332 add_trace("to", NULL, "CH(%lu)", port_id);
4333 if (dir == DIRECTION_IN)
4334 add_trace("from", NULL, "CH(%lu)", port_id);
4335 if (param->parkinfo.len)
4336 add_trace("length", NULL, "%d", param->parkinfo.len);
4341 case MESSAGE_BCHANNEL:
4342 trace_header("BCHANNEL", dir);
4343 switch(param->bchannel.type)
4345 case BCHANNEL_REQUEST:
4346 add_trace("type", NULL, "request");
4348 case BCHANNEL_ASSIGN:
4349 add_trace("type", NULL, "assign");
4351 case BCHANNEL_ASSIGN_ACK:
4352 add_trace("type", NULL, "assign_ack");
4354 case BCHANNEL_REMOVE:
4355 add_trace("type", NULL, "remove");
4357 case BCHANNEL_REMOVE_ACK:
4358 add_trace("type", NULL, "remove_ack");
4361 if (param->bchannel.addr)
4362 add_trace("address", NULL, "%x", param->bchannel.addr);
4368 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message_type);
4372 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, char *display)
4374 struct message *message;
4378 if (!portlist->port_id)
4381 if (!e_connectedmode)
4383 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4384 message->param.disconnectinfo.cause = cause;
4385 message->param.disconnectinfo.location = location;
4387 SCPY(message->param.disconnectinfo.display, display);
4389 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4392 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4394 SCPY(message->param.notifyinfo.display, display);
4396 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4398 message_put(message);
4399 logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);