1 /*****************************************************************************\
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg **
8 ** The EndpointAppPBX implements PBX4Linux **
10 \*****************************************************************************/
15 #include <sys/types.h>
24 class EndpointAppPBX *apppbx_first = NULL;
27 * EndpointAppPBX constructor
29 EndpointAppPBX::EndpointAppPBX(class Endpoint *epoint) : EndpointApp(epoint)
31 class EndpointAppPBX **apppointer;
33 /* add application to chain */
35 apppointer = &apppbx_first;
37 apppointer = &((*apppointer)->next);
41 memset(&e_ext, 0, sizeof(struct extension));
42 e_ext.rights = 4; /* international */
43 e_ext.rxvol = e_ext.txvol = 256;
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_call_tone[0] = e_hold_tone[0] = '\0';
68 e_call_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 = CAUSE_NOUSER;
88 e_multipoint_location = LOCATION_PRIVATE_LOCAL;
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_call_cause = e_call_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;
130 PERROR("error: endpoint not in endpoint's list, exitting.\n");
139 * trace header for application
141 void EndpointAppPBX::trace_header(char *name, int direction)
145 char msgtext[sizeof(_trace.name)];
149 /* init trace with given values */
150 start_trace(ea_endpoint->ep_serial,
152 numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype),
156 ea_endpoint->ep_serial,
163 /* set new endpoint state
165 void EndpointAppPBX::new_state(int state)
168 if (e_state != state)
170 trace_header("NEW STATE", DIRECTION_NONE);
171 add_trace("state", "old", "%s", state_name[e_state]);
172 add_trace("state", "new", "%s", state_name[state]);
181 * out==0: incomming caller id, out==1: outgoing caller id
183 void EndpointAppPBX::screen(int out, char *id, int idsize, int *type, int *present)
185 struct interface *interface;
187 struct interface_msn *ifmsn;
188 struct interface_screen *ifscreen;
191 interface = interface_first;
194 if (!strcmp(e_callerinfo.interface, interface->name))
198 interface = interface->next;
202 /* screen incoming caller id */
205 /* check for MSN numbers, use first MSN if no match */
207 ifmsn = interface->ifmsn;
212 if (!strcmp(ifmsn->msn, id))
220 trace_header("SCREEN (found in list)", DIRECTION_IN);
221 add_trace("msn", NULL, "%s", id);
224 if (!ifmsn && msn1) // not in list, first msn given
226 trace_header("SCREEN (not found in list)", DIRECTION_IN);
227 add_trace("msn", "given", "%s", id);
228 add_trace("msn", "used", "%s", msn1);
230 UNCPY(id, msn1, idsize);
235 /* check screen list */
237 ifscreen = interface->ifscreen_out;
239 ifscreen = interface->ifscreen_in;
242 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
243 if (ifscreen->match_present==-1 || ifscreen->match_present==*present)
245 if (strchr(ifscreen->match,'%'))
247 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
251 if (!strcmp(ifscreen->match, id))
255 ifscreen = ifscreen->next;
257 if (ifscreen) // match
259 trace_header("SCREEN (found in list)", out?DIRECTION_OUT:DIRECTION_IN);
262 case INFO_NTYPE_UNKNOWN:
263 add_trace("given", "type", "unknown");
265 case INFO_NTYPE_SUBSCRIBER:
266 add_trace("given", "type", "subscriber");
268 case INFO_NTYPE_NATIONAL:
269 add_trace("given", "type", "national");
271 case INFO_NTYPE_INTERNATIONAL:
272 add_trace("given", "type", "international");
277 case INFO_PRESENT_ALLOWED:
278 add_trace("given", "present", "allowed");
280 case INFO_PRESENT_RESTRICTED:
281 add_trace("given", "present", "restricted");
283 case INFO_PRESENT_NOTAVAIL:
284 add_trace("given", "present", "not available");
287 add_trace("given", "id", "%s", id[0]?id:"<empty>");
288 if (ifscreen->result_type != -1)
290 *type = ifscreen->result_type;
293 case INFO_NTYPE_UNKNOWN:
294 add_trace("used", "type", "unknown");
296 case INFO_NTYPE_SUBSCRIBER:
297 add_trace("used", "type", "subscriber");
299 case INFO_NTYPE_NATIONAL:
300 add_trace("used", "type", "national");
302 case INFO_NTYPE_INTERNATIONAL:
303 add_trace("used", "type", "international");
307 if (ifscreen->result_present != -1)
309 *present = ifscreen->result_present;
312 case INFO_PRESENT_ALLOWED:
313 add_trace("used", "present", "allowed");
315 case INFO_PRESENT_RESTRICTED:
316 add_trace("used", "present", "restricted");
318 case INFO_PRESENT_NOTAVAIL:
319 add_trace("used", "present", "not available");
323 if (strchr(ifscreen->match,'%'))
325 SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
326 UNCPY(id, ifscreen->result, idsize);
328 if (strchr(ifscreen->result,'%'))
330 *strchr(ifscreen->result,'%') = '\0';
331 UNCAT(id, suffix, idsize);
336 UNCPY(id, ifscreen->result, idsize);
339 add_trace("used", "id", "%s", id[0]?id:"<empty>");
345 /* release call and port (as specified)
347 void EndpointAppPBX::release(int release, int calllocation, int callcause, int portlocation, int portcause)
349 struct port_list *portlist;
350 struct message *message;
354 /* message to test call */
355 admin_call_response(e_adminid, ADMIN_CALL_RELEASE, "", callcause, calllocation, 0);
357 /* if a release is pending */
358 if (release==RELEASE_CALL || release==RELEASE_ALL || release==RELEASE_PORT_CALLONLY)
360 PDEBUG(DEBUG_EPOINT, "EPOINT(%d): do pending release (callcause %d location %d)\n", ea_endpoint->ep_serial, callcause, calllocation);
361 if (ea_endpoint->ep_call_id)
363 call = find_call_id(ea_endpoint->ep_call_id);
365 call->release(ea_endpoint->ep_serial, 0, calllocation, callcause);
367 ea_endpoint->ep_call_id = 0;
370 if (release != RELEASE_PORT_CALLONLY)
373 call_release(e_hold_id, ea_endpoint->ep_serial, 1, calllocation, callcause);
378 if (release==RELEASE_ALL || release==RELEASE_PORT_CALLONLY)
380 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release (portcause %d portlocation)\n", ea_endpoint->ep_serial, portcause, portlocation);
381 while((portlist = ea_endpoint->ep_portlist))
383 if (portlist->port_id)
385 SPRINT(cause, "cause_%02x", portcause);
386 set_tone(portlist, cause);
387 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
388 message->param.disconnectinfo.cause = portcause;
389 message->param.disconnectinfo.location = portlocation;
390 message_put(message);
393 ea_endpoint->free_portlist(portlist);
396 /* if callback is enabled, call back with the given caller id */
399 /* reset some stuff */
400 new_state(EPOINT_STATE_IDLE);
401 memset(&e_connectinfo, 0, sizeof(struct connect_info));
402 memset(&e_redirinfo, 0, sizeof(struct redir_info));
403 e_start = e_stop = 0;
404 e_ruleset = ruleset_main;
406 e_rule = e_ruleset->rule_first;
408 e_action_timeout = 0;
410 e_match_to_action = NULL;
412 e_extdialing = e_dialinginfo.id;
419 e_multipoint_cause = CAUSE_NOUSER;
420 e_multipoint_location = LOCATION_PRIVATE_LOCAL;
421 e_dialing_queue[0] = '\0';
423 e_crypt_state = CM_ST_NULL;
424 e_crypt_keyengine_busy = 0;
425 e_crypt_info[0] = '\0';
429 e_tx_state = NOTIFY_STATE_ACTIVE;
430 e_rx_state = NOTIFY_STATE_ACTIVE;
431 e_call_cause = e_call_location = 0;
433 /* the caller info of the callback user */
434 memcpy(&e_callbackinfo, &e_callerinfo, sizeof(e_callbackinfo));
435 memset(&e_dialinginfo, 0, sizeof(e_dialinginfo));
436 /* create dialing by callerinfo */
437 if (e_ext.number[0] && e_extension_interface[0])
439 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to internal: %s interface %s\n", ea_endpoint->ep_serial, e_ext.number, e_extension_interface);
440 /* create callback to the current terminal */
441 SCPY(e_dialinginfo.id, e_ext.number);
442 SCPY(e_dialinginfo.interfaces, e_extension_interface);
443 e_dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
444 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
449 SCPY(e_dialinginfo.id, e_cbto);
452 /* numberrize caller id and use it to dial to the callback */
453 SCPY(e_dialinginfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype));
455 e_dialinginfo.itype = INFO_ITYPE_ISDN;
456 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
457 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) preparing callback to external: %s\n", ea_endpoint->ep_serial, e_dialinginfo.id);
462 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do pending release of epoint itself.\n", ea_endpoint->ep_serial);
463 ea_endpoint->ep_use--; /* when e_lock is 0, the endpoint will be deleted */
469 /* cancel callerid if restricted, unless anon-ignore is enabled at extension or port is of type external (so called police gets caller id :)*/
470 void apply_callerid_restriction(int anon_ignore, char *id, int *ntype, int *present, int *screen, char *extension, char *name)
472 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");
474 /* caller id is not restricted, so we do nothing */
475 if (*present != INFO_PRESENT_RESTRICTED)
478 /* only extensions are restricted */
484 /* if we enabled anonymouse ignore */
488 /* else we remove the caller id */
492 *ntype = INFO_NTYPE_UNKNOWN;
494 // *screen = INFO_SCREEN_USER;
495 // maybe we should not make voip address anonymous
498 // maybe it's no fraud to present extension id
500 // extension[0] = '\0';
505 /* used display message to display callerid as available */
506 char *EndpointAppPBX::apply_callerid_display(char *id, int itype, int ntype, int present, int screen, char *extension, char *name)
508 static char display[81];
511 char *cid = numberrize_callerinfo(id, ntype);
513 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");
522 /* NOTE: is caller is is not available for this extesion, it has been removed by apply_callerid_restriction already */
524 /* internal extension's caller id */
525 if (extension[0] && e_ext.display_int)
528 SCAT(display, extension);
531 if (itype == INFO_ITYPE_VBOX)
532 SCAT(display, "(vbox)");
534 SCAT(display, "(int)");
537 /* external caller id */
538 if (!extension[0] && e_ext.display_ext)
544 if (present == INFO_PRESENT_RESTRICTED)
545 SCAT(display, "anonymous");
547 SCAT(display, "unknown");
554 /* display if callerid is anonymouse but available due anon-ignore */
555 if (e_ext.display_anon && present==INFO_PRESENT_RESTRICTED)
558 SCAT(display, "unknown");
561 SCAT(display, " anon");
564 /* display if callerid is anonymouse but available due anon-ignore */
565 if (e_ext.display_fake && screen==INFO_SCREEN_USER && present!=INFO_PRESENT_NULL)
571 if (present == INFO_PRESENT_RESTRICTED)
572 SCAT(display, "anonymous");
574 SCAT(display, "unknown");
579 SCAT(display, " fake");
583 if (name[0] && e_ext.display_name)
585 if (!display[0] && cid[0])
596 * uses the current state to notify activity
598 void EndpointAppPBX::notify_active(void)
600 struct port_list *portlist = ea_endpoint->ep_portlist;
601 struct message *message;
606 case NOTIFY_STATE_ACTIVE:
607 /* we are already active, so we don't do anything */
610 case NOTIFY_STATE_SUSPEND:
611 notify = INFO_NOTIFY_USER_RESUMED;
614 set_tone(portlist, NULL);
615 portlist = portlist->next;
617 portlist = ea_endpoint->ep_portlist;
620 case NOTIFY_STATE_HOLD:
621 notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
624 set_tone(portlist, NULL);
625 portlist = portlist->next;
627 portlist = ea_endpoint->ep_portlist;
630 case NOTIFY_STATE_CONFERENCE:
631 notify = INFO_NOTIFY_CONFERENCE_DISCONNECTED;
634 set_tone(portlist, NULL);
635 portlist = portlist->next;
637 portlist = ea_endpoint->ep_portlist;
641 PERROR("unknown e_tx_state = %d\n", e_tx_state);
647 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
648 message->param.notifyinfo.notify = notify;
649 message_put(message);
651 portlist = portlist->next;
657 * keypad functions during call. one example to use this is to put a call on hold or start a conference
659 void EndpointAppPBX::keypad_function(char digit)
662 /* we must be in a call, in order to send messages to the call */
663 if (e_ext.number[0] == '\0')
665 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) IGNORING keypad received not from extension.\n", ea_endpoint->ep_serial);
671 /* join conference */
673 if (ea_endpoint->ep_call_id == 0)
675 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad received during connect but not during a call.\n", ea_endpoint->ep_serial);
678 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) join call with call on hold\n", ea_endpoint->ep_serial);
684 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) shared key encryption selected.\n", ea_endpoint->ep_serial);
688 /* crypt key-exchange */
690 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) key exchange encryption selected.\n", ea_endpoint->ep_serial);
696 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) encryption off selected.\n", ea_endpoint->ep_serial);
701 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported keypad digit '%c'.\n", ea_endpoint->ep_serial, digit);
706 /* set tone pattern for port */
707 void EndpointAppPBX::set_tone(struct port_list *portlist, char *tone)
709 struct message *message;
714 /* store for suspended processes */
719 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no endpoint to notify tone.\n", ea_endpoint->ep_serial);
723 if (e_call_pattern /* pattern are provided */
724 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_SETUP)
725 && !(e_ext.own_setup && e_state == EPOINT_STATE_IN_OVERLAP)
726 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_IN_PROCEEDING)
727 && !(e_ext.own_alerting && e_state == EPOINT_STATE_IN_ALERTING)
728 && !(e_ext.own_cause && e_state == EPOINT_STATE_IN_DISCONNECT)
729 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_SETUP)
730 && !(e_ext.own_setup && e_state == EPOINT_STATE_OUT_OVERLAP)
731 && !(e_ext.own_proceeding && e_state == EPOINT_STATE_OUT_PROCEEDING)
732 && !(e_ext.own_alerting && e_state == EPOINT_STATE_OUT_ALERTING)
733 && !(e_ext.own_cause && e_state == EPOINT_STATE_OUT_DISCONNECT)
734 && tone[0] && !!strncmp(tone,"crypt_*",6))
736 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) tone not provided since patterns are available\n", ea_endpoint->ep_serial);
742 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_TONE);
743 SCPY(message->param.tone.dir, e_ext.tones_dir[0]?e_ext.tones_dir:options.tones_dir);
744 SCPY(message->param.tone.name, tone);
745 message_put(message);
752 * hunts an mISDNport that is available for an outgoing call
753 * if no ifname was given, any interface that is not an extension
756 struct mISDNport *EndpointAppPBX::hunt_port(char *ifname, int *channel)
758 struct interface *interface;
759 struct interface_port *ifport, *ifport_start;
760 struct select_channel *selchannel;
761 struct mISDNport *mISDNport;
764 interface = interface_first;
766 /* first find the given interface or, if not given, one with no extension */
771 /* check for given interface */
774 if (!strcasecmp(interface->name, ifname))
776 /* found explicit interface */
777 trace_header("CHANNEL SELECTION (found interface)", DIRECTION_NONE);
778 add_trace("interface", NULL, "%s", ifname);
785 if (!interface->extension)
787 /* found non extension */
788 trace_header("CHANNEL SELECTION (found non extension interface)", DIRECTION_NONE);
789 add_trace("interface", NULL, "%s", interface->name);
795 interface = interface->next;
799 /* see if interface has ports */
800 if (!interface->ifport)
803 trace_header("CHANNEL SELECTION (interface has no active ports, skipping)", DIRECTION_NONE);
804 add_trace("interface", NULL, "%s", interface->name);
806 interface = interface->next;
810 /* select port by algorithm */
811 ifport_start = interface->ifport;
813 if (interface->hunt == HUNT_ROUNDROBIN)
815 while(ifport_start->next && index<interface->hunt_next)
817 ifport_start = ifport_start->next;
820 trace_header("CHANNEL SELECTION (starting round-robin)", DIRECTION_NONE);
821 add_trace("port", NULL, "%d", ifport_start->portnum);
822 add_trace("position", NULL, "%d", index);
827 ifport = ifport_start;
830 /* see if port is available */
831 if (!ifport->mISDNport)
833 trace_header("CHANNEL SELECTION (port not available, skipping)", DIRECTION_NONE);
834 add_trace("port", NULL, "%d", ifport->portnum);
835 add_trace("position", NULL, "%d", index);
839 mISDNport = ifport->mISDNport;
841 /* see if port is administratively blocked */
844 trace_header("CHANNEL SELECTION (port blocked by admin, skipping)", DIRECTION_NONE);
845 add_trace("port", NULL, "%d", ifport->portnum);
846 add_trace("position", NULL, "%d", index);
851 /* see if link is up */
852 if (mISDNport->ptp && !mISDNport->l2link)
854 trace_header("CHANNEL SELECTION (port is ptp with layer 2 down, skipping)", DIRECTION_NONE);
855 add_trace("port", NULL, "%d", ifport->portnum);
856 add_trace("position", NULL, "%d", index);
861 /* check for channel form selection list */
863 selchannel = ifport->out_channel;
866 switch(selchannel->channel)
868 case CHANNEL_FREE: /* free channel */
869 if (mISDNport->b_reserved >= mISDNport->b_num)
870 break; /* all channel in use or reserverd */
873 while(i < mISDNport->b_num)
875 if (mISDNport->b_port[i] == NULL)
877 *channel = i+1+(i>=15);
878 trace_header("CHANNEL SELECTION (selecting free channel)", DIRECTION_NONE);
879 add_trace("port", NULL, "%d", ifport->portnum);
880 add_trace("position", NULL, "%d", index);
881 add_trace("channel", NULL, "%d", *channel);
889 case CHANNEL_ANY: /* don't ask for channel */
890 if (mISDNport->b_reserved >= mISDNport->b_num)
892 break; /* all channel in use or reserverd */
894 trace_header("CHANNEL SELECTION (using 'any channel')", DIRECTION_NONE);
895 add_trace("port", NULL, "%d", ifport->portnum);
896 add_trace("position", NULL, "%d", index);
898 *channel = CHANNEL_ANY;
901 case CHANNEL_NO: /* call waiting */
902 trace_header("CHANNEL SELECTION (using 'no channel', call-waiting)", DIRECTION_NONE);
903 add_trace("port", NULL, "%d", ifport->portnum);
904 add_trace("position", NULL, "%d", index);
906 *channel = CHANNEL_NO;
910 if (selchannel->channel<1 || selchannel->channel==16)
911 break; /* invalid channels */
912 i = selchannel->channel-1-(selchannel->channel>=17);
913 if (i >= mISDNport->b_num)
914 break; /* channel not in port */
915 if (mISDNport->b_port[i] == NULL)
917 *channel = selchannel->channel;
918 trace_header("CHANNEL SELECTION (selecting given channel)", DIRECTION_NONE);
919 add_trace("port", NULL, "%d", ifport->portnum);
920 add_trace("position", NULL, "%d", index);
921 add_trace("channel", NULL, "%d", *channel);
928 break; /* found channel */
929 selchannel = selchannel->next;
932 /* if channel was found, return mISDNport and channel */
935 /* setting next port to start next time */
936 if (interface->hunt == HUNT_ROUNDROBIN)
941 interface->hunt_next = index;
947 trace_header("CHANNEL SELECTION (skipping, no channel found)", DIRECTION_NONE);
948 add_trace("port", NULL, "%d", ifport->portnum);
949 add_trace("position", NULL, "%d", index);
953 /* go next port, until all ports are checked */
955 ifport = ifport->next;
959 ifport = interface->ifport;
961 if (ifport != ifport_start)
964 return(NULL); /* no port found */
967 /* outgoing setup to port(s)
968 * ports will be created and a setup is sent if everything is ok. otherwhise
969 * the endpoint is destroyed.
971 void EndpointAppPBX::out_setup(void)
973 struct dialing_info dialinginfo;
975 // class pdss1 *pdss1;
976 struct port_list *portlist;
977 struct message *message;
979 int cause = CAUSE_RESSOURCEUNAVAIL;
982 struct mISDNport *mISDNport;
985 class EndpointAppPBX *atemp;
986 // char allowed_ports[256];
988 char ifname[sizeof(e_ext.interfaces)],
990 struct port_settings port_settings;
994 /* create settings for creating port */
995 memset(&port_settings, 0, sizeof(port_settings));
997 SCPY(port_settings.tones_dir, e_ext.tones_dir);
999 SCPY(port_settings.tones_dir, options.tones_dir);
1000 port_settings.tout_setup = e_ext.tout_setup;
1001 port_settings.tout_dialing = e_ext.tout_dialing;
1002 port_settings.tout_proceeding = e_ext.tout_proceeding;
1003 port_settings.tout_alerting = e_ext.tout_alerting;
1004 port_settings.tout_disconnect = e_ext.tout_disconnect;
1005 // port_settings.tout_hold = e_ext.tout_hold;
1006 // port_settings.tout_park = e_ext.tout_park;
1007 port_settings.no_seconds = e_ext.no_seconds;
1009 /* 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 */
1011 /* check what dialinginfo.itype we got */
1012 switch(e_dialinginfo.itype)
1014 /* *********************** call to extension or vbox */
1015 case INFO_ITYPE_ISDN_EXTENSION:
1016 /* check if we deny incoming calls when we use an extension */
1017 if (e_ext.noknocking)
1019 atemp = apppbx_first;
1023 if (!strcmp(atemp->e_ext.number, e_ext.number))
1025 atemp = atemp->next;
1029 PERROR("EPOINT(%d) noknocking and currently a call\n", ea_endpoint->ep_serial);
1030 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_BUSY, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYSPE_ call, port */
1031 return; /* must exit here */
1034 /* FALL THROUGH !!!! */
1035 case INFO_ITYPE_VBOX:
1036 /* get dialed extension's info */
1037 // SCPY(exten, e_dialinginfo.id);
1038 // if (strchr(exten, ','))
1039 // *strchr(exten, ',') = '\0';
1040 // if (!read_extension(&e_ext, exten))
1041 if (!read_extension(&e_ext, e_dialinginfo.id))
1043 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) extension %s not configured\n", ea_endpoint->ep_serial, e_dialinginfo.id);
1044 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_OUTOFORDER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, call, port */
1045 return; /* must exit here */
1048 if (e_dialinginfo.itype == INFO_ITYPE_VBOX)
1050 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing directly to VBOX\n", ea_endpoint->ep_serial);
1055 /* string from unconditional call forward (cfu) */
1059 /* present to forwarded party */
1060 if (e_ext.anon_ignore && e_callerinfo.id[0])
1062 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1064 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
1068 /* string from busy call forward (cfb) */
1072 class EndpointAppPBX *checkapp = apppbx_first;
1075 if (checkapp != this) /* any other endpoint except our own */
1077 if (!strcmp(checkapp->e_ext.number, e_ext.number))
1079 /* present to forwarded party */
1080 if (e_ext.anon_ignore && e_callerinfo.id[0])
1082 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1084 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
1088 checkapp = checkapp->next;
1092 /* string from no-response call forward (cfnr) */
1096 /* when cfnr is done, out_setup() will setup the call */
1099 /* present to forwarded party */
1100 if (e_ext.anon_ignore && e_callerinfo.id[0])
1102 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1106 if (!!strcmp(p, "vbox") || (e_capainfo.bearer_capa==INFO_BC_AUDIO) || (e_capainfo.bearer_capa==INFO_BC_SPEECH))
1108 e_cfnr_release = now + e_ext.cfnr_delay;
1109 e_cfnr_call = now + e_ext.cfnr_delay + 1; /* call one second after release */
1110 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);
1114 /* call to all internal interfaces */
1115 p = e_ext.interfaces;
1116 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) generating multiple calls for extension %s to interfaces %s\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1120 while(*p!=',' && *p!='\0')
1122 SCCAT(ifname, *p++);
1125 /* found interface */
1126 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) calling to interface %s\n", ea_endpoint->ep_serial, ifname);
1127 /* hunt for mISDNport and create Port */
1128 mISDNport = hunt_port(ifname, &channel);
1131 trace_header("INTERFACE (not found or busy)", DIRECTION_NONE);
1132 add_trace("interface", NULL, "%s", ifname);
1136 /* creating INTERNAL port */
1137 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1138 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force);
1141 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port '%s' failed to create\n", ea_endpoint->ep_serial, mISDNport->ifport->interface->name);
1142 goto check_anycall_intern;
1144 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
1145 memset(&dialinginfo, 0, sizeof(dialinginfo));
1146 SCPY(dialinginfo.id, e_dialinginfo.id);
1147 dialinginfo.itype = INFO_ITYPE_ISDN_EXTENSION;
1148 dialinginfo.ntype = e_dialinginfo.ntype;
1149 /* create port_list relation */
1150 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1153 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1155 goto check_anycall_intern;
1157 /* directory.list */
1158 if (e_callerinfo.id[0] && (e_ext.centrex || e_ext.display_name))
1160 dirname = parse_directory(e_callerinfo.id, e_callerinfo.ntype);
1162 SCPY(e_callerinfo.name, dirname);
1164 // dss1 = (class Pdss1 *)port;
1166 //printf("INTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1167 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1168 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1169 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1170 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1171 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1172 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1173 //terminal if (e_dialinginfo.id)
1174 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1175 /* handle restricted caller ids */
1176 apply_callerid_restriction(e_ext.anon_ignore, 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);
1177 apply_callerid_restriction(e_ext.anon_ignore, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1178 /* display callerid if desired for extension */
1179 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));
1180 //printf("\n\ndisplay = %s\n\n\n",message->param.setup.callerinfo.display);
1181 /* use cnip, if enabld */
1183 message->param.setup.callerinfo.name[0] = '\0';
1184 /* screen clip if prefix is required */
1185 if (message->param.setup.callerinfo.id[0] && e_ext.clip_prefix[0])
1187 SCPY(message->param.setup.callerinfo.id, e_ext.clip_prefix);
1188 SCAT(message->param.setup.callerinfo.id, numberrize_callerinfo(e_callerinfo.id,e_callerinfo.ntype));
1189 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1191 /* use internal caller id */
1192 if (e_callerinfo.extension[0] && (message->param.setup.callerinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore))
1194 SCPY(message->param.setup.callerinfo.id, e_callerinfo.extension);
1195 message->param.setup.callerinfo.ntype = INFO_NTYPE_UNKNOWN;
1197 message_put(message);
1198 logmessage(message);
1202 /* string from parallel call forward (cfp) */
1206 if (e_ext.anon_ignore && e_callerinfo.id[0])
1208 e_callerinfo.present = INFO_PRESENT_ALLOWED;
1212 vbox_only: /* entry point for answering machine only */
1213 cfu_only: /* entry point for cfu */
1214 cfb_only: /* entry point for cfb */
1215 cfnr_only: /* entry point for cfnr */
1216 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call extension %s for external destiantion(s) '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id, p);
1221 /* only if vbox should be dialed, and terminal is given */
1222 if (!strcmp(p, "vbox") && e_ext.number[0])
1224 /* go to the end of p */
1227 /* answering vbox call */
1228 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) answering machine\n", ea_endpoint->ep_serial);
1230 if (!(port = new VBoxPort(PORT_TYPE_VBOX_OUT, &port_settings)))
1232 PERROR("EPOINT(%d) no mem for port\n", ea_endpoint->ep_serial);
1235 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) allocated port %s\n", ea_endpoint->ep_serial, port->p_name);
1236 UCPY(cfp, e_ext.number); /* cfp or any other direct forward/vbox */
1240 while(*p!=',' && *p!='\0')
1245 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cfp external %s\n", ea_endpoint->ep_serial, cfp);
1246 /* hunt for mISDNport and create Port */
1247 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1250 /* creating EXTERNAL port*/
1251 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1252 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force);
1253 earlyb = mISDNport->earlyb;
1257 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1258 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1264 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no port found or created, which is idle.\n", ea_endpoint->ep_serial);
1265 goto check_anycall_intern;
1267 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found or created port %s\n", ea_endpoint->ep_serial, port->p_name);
1268 memset(&dialinginfo, 0, sizeof(dialinginfo));
1269 SCPY(dialinginfo.id, cfp);
1270 dialinginfo.itype = INFO_ITYPE_ISDN;
1271 dialinginfo.ntype = e_dialinginfo.ntype;
1272 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, earlyb);
1275 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1277 goto check_anycall_intern;
1279 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1280 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1281 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1282 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1283 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1284 /* if clip is hidden */
1285 if (e_ext.clip==CLIP_HIDE && port->p_type!=PORT_TYPE_VBOX_OUT)
1287 SCPY(message->param.setup.callerinfo.id, e_ext.callerid);
1288 SCPY(message->param.setup.callerinfo.extension, e_ext.number);
1289 message->param.setup.callerinfo.ntype = e_ext.callerid_type;
1290 message->param.setup.callerinfo.present = e_ext.callerid_present;
1292 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1293 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1294 //terminal if (e_dialinginfo.id)
1295 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1296 /* handle restricted caller ids */
1297 apply_callerid_restriction(e_ext.anon_ignore, 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);
1298 apply_callerid_restriction(e_ext.anon_ignore, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1299 /* display callerid if desired for extension */
1300 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));
1301 message_put(message);
1302 logmessage(message);
1306 check_anycall_intern:
1307 /* now we have all ports created */
1310 trace_header("INTERFACE (no extension's interface)", DIRECTION_NONE);
1312 if (!ea_endpoint->ep_call_id)
1314 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, call, port */
1315 return; /* must exit here */
1319 /* *********************** external call */
1321 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing external: '%s'\n", ea_endpoint->ep_serial, e_dialinginfo.id);
1322 /* call to extenal interfaces */
1323 p = e_dialinginfo.id;
1327 while(*p!=',' && *p!='\0')
1328 SCCAT(number, *p++);
1332 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");
1333 /* hunt for mISDNport and create Port */
1334 /* hunt for mISDNport and create Port */
1335 mISDNport = hunt_port(e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:NULL, &channel);
1338 /* creating EXTERNAL port*/
1339 SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
1340 port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force);
1341 earlyb = mISDNport->earlyb;
1344 trace_header("INTERFACE (too busy)", DIRECTION_NONE);
1345 add_trace("interface", NULL, "%s", e_dialinginfo.interfaces[0]?e_dialinginfo.interfaces:"any interface");
1347 goto check_anycall_extern;
1351 PERROR("EPOINT(%d) no memory for external port, exitting\n", ea_endpoint->ep_serial);
1354 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
1355 memset(&dialinginfo, 0, sizeof(dialinginfo));
1356 SCPY(dialinginfo.id, number);
1357 dialinginfo.itype = INFO_ITYPE_ISDN;
1358 dialinginfo.ntype = e_dialinginfo.ntype;
1359 portlist = ea_endpoint->portlist_new(port->p_serial, port->p_type, mISDNport->earlyb);
1362 PERROR("EPOINT(%d) cannot allocate port_list relation\n", ea_endpoint->ep_serial);
1364 goto check_anycall_extern;
1366 // dss1 = (class Pdss1 *)port;
1367 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
1368 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
1369 memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
1370 SCPY(message->param.setup.dialinginfo.id, number);
1371 memcpy(&message->param.setup.redirinfo, &e_redirinfo, sizeof(struct redir_info));
1372 memcpy(&message->param.setup.callerinfo, &e_callerinfo, sizeof(struct caller_info));
1373 memcpy(&message->param.setup.capainfo, &e_capainfo, sizeof(struct capa_info));
1374 //terminal SCPY(message->param.setup.from_terminal, e_ext.number);
1375 //terminal if (e_dialinginfo.id)
1376 //terminal SCPY(message->param.setup.to_terminal, e_dialinginfo.id);
1377 /* handle restricted caller ids */
1378 apply_callerid_restriction(e_ext.anon_ignore, 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);
1379 apply_callerid_restriction(e_ext.anon_ignore, message->param.setup.redirinfo.id, &message->param.setup.redirinfo.ntype, &message->param.setup.redirinfo.present, 0, message->param.setup.redirinfo.extension, NULL);
1380 /* display callerid if desired for extension */
1381 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));
1382 message_put(message);
1383 logmessage(message);
1387 check_anycall_extern:
1388 /* now we have all ports created */
1391 trace_header("INTERFACE (no free ports found)", DIRECTION_NONE);
1393 if (!ea_endpoint->ep_call_id)
1395 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOCHANNEL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, call, port */
1396 return; /* must exit here */
1404 /* handler for endpoint
1408 int EndpointAppPBX::handler(void)
1410 if (e_crypt_state!=CM_ST_NULL)
1415 /* process answering machine (play) handling */
1418 if (e_action->index == ACTION_VBOX_PLAY)
1421 /* process action timeout */
1422 if (e_action_timeout)
1423 if (now_d >= e_action_timeout)
1425 if (e_state!=EPOINT_STATE_CONNECT)
1428 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current action timed out.\n", ea_endpoint->ep_serial);
1429 e_multipoint_cause = CAUSE_NOUSER;
1430 e_multipoint_location = LOCATION_PRIVATE_LOCAL;
1431 new_state(EPOINT_STATE_IN_OVERLAP);
1434 return(1); /* we must exit, because our endpoint might be gone */
1436 e_action_timeout = 0;
1439 /* process action timeout */
1440 if (e_match_timeout)
1441 if (now_d >= e_match_timeout)
1444 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we got a match timeout.\n", ea_endpoint->ep_serial);
1446 return(1); /* we must exit, because our endpoint might be gone */
1451 /* process redialing (epoint redials to port) */
1454 if (now_d >= e_redial)
1457 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial.\n", ea_endpoint->ep_serial);
1459 new_state(EPOINT_STATE_OUT_SETUP);
1460 /* call special setup routine */
1467 /* process powerdialing (epoint redials to epoint) */
1468 if (e_powerdialing > 0)
1470 if (now_d >= e_powerdialing)
1472 e_powerdialing = -1; /* leave power dialing on */
1473 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting redial of powerdial.\n", ea_endpoint->ep_serial);
1476 e_ruleset = ruleset_main;
1478 e_rule = e_ruleset->rule_first;
1480 new_state(EPOINT_STATE_IN_OVERLAP);
1486 /* process call forward no response */
1489 struct port_list *portlist;
1490 struct message *message;
1492 if (now >= e_cfnr_release)
1494 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-no-response time has expired, hanging up.\n", ea_endpoint->ep_serial);
1497 /* release all ports */
1498 while((portlist = ea_endpoint->ep_portlist))
1500 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
1501 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
1502 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
1503 message_put(message);
1504 logmessage(message);
1505 ea_endpoint->free_portlist(portlist);
1508 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
1509 message->param.channel = CHANNEL_STATE_HOLD;
1510 message_put(message);
1511 /* indicate no patterns */
1512 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_NOPATTERN);
1513 message_put(message);
1514 /* set setup state, since we have no response from the new call */
1515 new_state(EPOINT_STATE_OUT_SETUP);
1520 if (now >= e_cfnr_call)
1522 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call-forward-busy time has expired, calling the forwarded number: %s.\n", ea_endpoint->ep_serial, e_ext.cfnr);
1528 /* handle connection to user */
1529 if (e_state == EPOINT_STATE_IDLE)
1531 /* epoint is idle, check callback */
1533 if (now_d >= e_callback)
1535 e_callback = 0; /* done with callback */
1536 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) starting callback.\n", ea_endpoint->ep_serial);
1537 new_state(EPOINT_STATE_OUT_SETUP);
1543 /* check for password timeout */
1545 if (e_action->index==ACTION_PASSWORD || e_action->index==ACTION_PASSWORD_WRITE)
1547 struct port_list *portlist;
1549 if (now >= e_password_timeout)
1551 e_ruleset = ruleset_main;
1553 e_rule = e_ruleset->rule_first;
1555 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) password timeout %s\n", ea_endpoint->ep_serial, e_extdialing);
1556 trace_header("PASSWORD timeout", DIRECTION_NONE);
1558 e_connectedmode = 0;
1560 new_state(EPOINT_STATE_OUT_DISCONNECT);
1561 portlist = ea_endpoint->ep_portlist;
1564 message_disconnect_port(portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
1565 set_tone(portlist, "cause_10");
1575 /* doing a hookflash */
1576 void EndpointAppPBX::hookflash(void)
1580 /* be sure that we are active */
1582 e_tx_state = NOTIFY_STATE_ACTIVE;
1584 trace_header("HOOKFLASH DTMF", DIRECTION_NONE);
1586 if (ea_endpoint->ep_use > 1)
1588 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot hooflash while child process is running.\n", ea_endpoint->ep_serial);
1591 /* dialtone after pressing the hash key */
1592 process_hangup(e_call_cause, e_call_location);
1593 e_multipoint_cause = CAUSE_NOUSER;
1594 e_multipoint_location = LOCATION_PRIVATE_LOCAL;
1595 port = find_port_id(ea_endpoint->ep_portlist->port_id);
1598 port->set_echotest(0);
1600 if (ea_endpoint->ep_call_id)
1602 release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, call, port */
1604 e_ruleset = ruleset_main;
1606 e_rule = e_ruleset->rule_first;
1608 new_state(EPOINT_STATE_IN_OVERLAP);
1609 e_connectedmode = 1;
1610 SCPY(e_dialinginfo.id, e_ext.prefix);
1611 e_extdialing = e_dialinginfo.id;
1613 if (e_dialinginfo.id[0])
1615 set_tone(ea_endpoint->ep_portlist, "dialing");
1619 set_tone(ea_endpoint->ep_portlist, "dialpbx");
1626 /* messages from port
1628 /* port MESSAGE_SETUP */
1629 void EndpointAppPBX::port_setup(struct port_list *portlist, int message_type, union parameter *param)
1631 struct message *message;
1633 int writeext; /* flags need to write extension after modification */
1636 portlist->port_type = param->setup.port_type;
1637 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
1638 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
1639 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
1640 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
1641 e_dtmf = param->setup.dtmf;
1643 /* screen incoming caller id */
1644 screen(0, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present);
1646 /* process extension */
1647 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1649 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is extension\n", ea_endpoint->ep_serial);
1650 /* port makes call from extension */
1651 SCPY(e_callerinfo.extension, e_callerinfo.id);
1652 SCPY(e_ext.number, e_callerinfo.extension);
1653 SCPY(e_extension_interface, e_callerinfo.interface);
1656 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming call is external or voip\n", ea_endpoint->ep_serial);
1658 trace_header("SETUP", DIRECTION_IN);
1659 if (e_callerinfo.extension[0])
1660 add_trace("extension", NULL, "%s", e_callerinfo.extension);
1661 add_trace("caller id", "number", "%s", numberrize_callerinfo(e_callerinfo.id, e_callerinfo.ntype));
1662 if (e_callerinfo.present == INFO_PRESENT_RESTRICTED)
1663 add_trace("caller id", "present", "restricted");
1664 if (e_redirinfo.id[0])
1666 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(e_redirinfo.id, e_redirinfo.ntype));
1667 if (e_redirinfo.present == INFO_PRESENT_RESTRICTED)
1668 add_trace("redir'ing", "present", "restricted");
1670 if (e_dialinginfo.id)
1671 add_trace("dialing", "number", "%s", e_dialinginfo.id);
1674 if (e_callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1676 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
1678 /* get extension's info about caller */
1679 if (!read_extension(&e_ext, e_ext.number))
1681 /* extension doesn't exist */
1682 trace_header("EXTENSION (not created)", DIRECTION_IN);
1683 add_trace("extension", NULL, "%s", e_ext.number);
1685 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
1686 new_state(EPOINT_STATE_OUT_DISCONNECT);
1687 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
1688 e_ext.number[0] = '\0'; /* no terminal */
1693 /* put prefix (next) in front of e_dialinginfo.id */
1696 SPRINT(buffer, "%s%s", e_ext.next, e_dialinginfo.id);
1697 SCPY(e_dialinginfo.id, buffer);
1698 e_ext.next[0] = '\0';
1700 } else if (e_ext.prefix[0])
1702 SPRINT(buffer, "%s%s", e_ext.prefix, e_dialinginfo.id);
1703 SCPY(e_dialinginfo.id, buffer);
1706 /* screen caller id by extension's config */
1707 e_callerinfo.screen = INFO_SCREEN_NETWORK;
1709 SCPY(e_callerinfo.name, e_ext.name);
1710 /* use caller id (or if exist: id_next_call) for this call */
1711 if (e_ext.id_next_call_present >= 0)
1713 SCPY(e_callerinfo.id, e_ext.id_next_call);
1714 /* if we restrict the pesentation */
1715 if (e_ext.id_next_call_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1716 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1717 else e_callerinfo.present = e_ext.id_next_call_present;
1718 e_callerinfo.ntype = e_ext.id_next_call_type;
1719 e_ext.id_next_call_present = -1;
1723 SCPY(e_callerinfo.id, e_ext.callerid);
1724 /* if we restrict the pesentation */
1725 if (e_ext.callerid_present==INFO_PRESENT_ALLOWED && e_callerinfo.present==INFO_PRESENT_RESTRICTED)
1726 e_callerinfo.present = INFO_PRESENT_RESTRICTED;
1727 else e_callerinfo.present = e_ext.callerid_present;
1728 e_callerinfo.ntype = e_ext.callerid_type;
1731 /* extension is written */
1733 write_extension(&e_ext, e_ext.number);
1735 /* set volume of rx and tx */
1736 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
1737 if (e_ext.txvol!=256 || e_ext.rxvol!=256)
1739 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
1740 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
1741 message->param.mISDNsignal.rxvol = e_ext.txvol;
1742 message->param.mISDNsignal.txvol = e_ext.rxvol;
1743 message_put(message);
1746 /* start recording if enabled */
1747 if (e_ext.record!=CODEC_OFF && (e_capainfo.bearer_capa==INFO_BC_SPEECH || e_capainfo.bearer_capa==INFO_BC_AUDIO))
1749 /* check if we are a terminal */
1750 if (e_ext.number[0] == '\0')
1751 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
1754 port = find_port_id(portlist->port_id);
1756 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
1761 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call from external port\n", ea_endpoint->ep_serial);
1762 /* no terminal identification */
1763 e_ext.number[0] = '\0';
1764 e_extension_interface[0] = '\0';
1765 memset(&e_ext, 0, sizeof(e_ext));
1766 e_ext.rights = 4; /* right to dial internat */
1770 e_ruleset = ruleset_main;
1772 e_rule = e_ruleset->rule_first;
1774 e_extdialing = e_dialinginfo.id;
1775 new_state(EPOINT_STATE_IN_SETUP);
1776 if (e_dialinginfo.id[0])
1778 set_tone(portlist, "dialing");
1781 if (e_ext.number[0])
1782 set_tone(portlist, "dialpbx");
1784 set_tone(portlist, "dialtone");
1787 if (e_state == EPOINT_STATE_IN_SETUP)
1789 /* request MORE info, if not already at higher state */
1790 new_state(EPOINT_STATE_IN_OVERLAP);
1791 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_OVERLAP);
1792 message_put(message);
1793 logmessage(message);
1797 /* port MESSAGE_INFORMATION */
1798 void EndpointAppPBX::port_information(struct port_list *portlist, int message_type, union parameter *param)
1800 trace_header("INFORMATION", DIRECTION_IN);
1801 add_trace("dialing", NULL, "%s", param->information.id);
1802 if (param->information.sending_complete)
1803 add_trace("complete", NULL, NULL);
1807 /* turn off dtmf detection, in case dtmf is sent with keypad information */
1810 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received dialing information, so dtmf is now disabled, to prevent double detection by keypad+dtmf.\n", ea_endpoint->ep_serial, param->information.id, e_ext.number, e_callerinfo.id);
1814 /* if vbox_play is done, the information are just used as they come */
1816 if (e_action->index == ACTION_VBOX_PLAY)
1818 /* concat dialing string */
1819 SCAT(e_dialinginfo.id, param->information.id);
1824 /* keypad when disconnect but in connected mode */
1825 if (e_state==EPOINT_STATE_OUT_DISCONNECT && e_connectedmode)
1827 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received after disconnect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1828 /* processing keypad function */
1829 if (param->information.id[0] == '0')
1836 /* keypad when connected */
1837 if (e_state == EPOINT_STATE_CONNECT && e_ext.keypad)
1839 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) keypad information received during connect: %s.\n", ea_endpoint->ep_serial, param->information.id);
1840 /* processing keypad function */
1841 if (param->information.id[0] == '0')
1845 if (param->information.id[0])
1846 keypad_function(param->information.id[0]);
1849 if (e_state != EPOINT_STATE_IN_OVERLAP)
1851 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in overlap, or connect state.\n", ea_endpoint->ep_serial);
1854 if (!param->information.id[0])
1856 if (e_dialinginfo.id[0]=='\0' && !e_action)
1858 set_tone(portlist, "dialing");
1861 if (e_action->index==ACTION_OUTDIAL
1862 || e_action->index==ACTION_EXTERNAL)
1865 set_tone(portlist, "dialing");
1866 else if (!e_extdialing[0])
1867 set_tone(portlist, "dialing");
1869 /* concat dialing string */
1870 SCAT(e_dialinginfo.id, param->information.id);
1874 /* port MESSAGE_DTMF */
1875 void EndpointAppPBX::port_dtmf(struct port_list *portlist, int message_type, union parameter *param)
1877 trace_header("DTMF", DIRECTION_IN);
1878 add_trace("digit", NULL, "%c", param->dtmf);
1880 /* only if dtmf detection is enabled */
1883 PDEBUG(DEBUG_EPOINT, "dtmf detection is disabled\n");
1888 NOTE: vbox is now handled due to overlap state
1889 /* if vbox_play is done, the dtmf digits are just used as they come */
1891 if (e_action->index == ACTION_VBOX_PLAY)
1893 /* concat dialing string */
1894 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id))
1896 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1897 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1900 /* continue to process *X# sequences */
1904 /* check for *X# sequence */
1905 if (e_state == EPOINT_STATE_CONNECT)
1907 if (e_dtmf_time+3 < now)
1909 /* the last digit was too far in the past to be a sequence */
1910 if (param->dtmf == '*')
1911 /* only start is allowed in the sequence */
1917 /* we have a sequence of digits, see what we got */
1918 if (param->dtmf == '*')
1920 else if (param->dtmf>='0' && param->dtmf<='9')
1922 /* we need to have a star before we receive the digit of the sequence */
1923 if (e_dtmf_last == '*')
1924 e_dtmf_last = param->dtmf;
1925 } else if (param->dtmf == '#')
1928 if (e_dtmf_last>='0' && e_dtmf_last<='9')
1930 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dtmf sequence *%c# detected.\n", ea_endpoint->ep_serial, e_dtmf_last);
1931 if (e_dtmf_last == '0')
1936 /* processing keypad function */
1938 keypad_function(e_dtmf_last);
1944 /* set last time of dtmf */
1949 /* check for ## hookflash during dialing */
1951 if (e_action->index==ACTION_PASSWORD
1952 || e_action->index==ACTION_PASSWORD_WRITE)
1954 if (param->dtmf=='#') /* current digit is '#' */
1956 if (e_state==EPOINT_STATE_IN_DISCONNECT
1957 || (e_state!=EPOINT_STATE_CONNECT && e_dtmf_time+3>=now && e_dtmf_last=='#')) /* when disconnected, just #. when dialing, ##. */
1974 /* dialing using dtmf digit */
1975 if (e_state==EPOINT_STATE_IN_OVERLAP)// && e_state==e_connectedmode)
1977 if (e_dialinginfo.id[0]=='\0' && !e_action)
1979 set_tone(portlist, "dialing");
1981 /* concat dialing string */
1982 if (strlen(e_dialinginfo.id)+1 < sizeof(e_dialinginfo.id))
1984 e_dialinginfo.id[strlen(e_dialinginfo.id)+1] = '\0';
1985 e_dialinginfo.id[strlen(e_dialinginfo.id)] = param->dtmf;
1991 /* port MESSAGE_CRYPT */
1992 void EndpointAppPBX::port_crypt(struct port_list *portlist, int message_type, union parameter *param)
1994 /* send crypt response to cryptman */
1995 if (param->crypt.type == CR_MESSAGE_IND)
1996 cryptman_msg2man(param->crypt.data, param->crypt.len);
1998 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2001 /* port MESSAGE_OVERLAP */
2002 void EndpointAppPBX::port_overlap(struct port_list *portlist, int message_type, union parameter *param)
2004 struct message *message;
2006 /* signal to call tool */
2007 admin_call_response(e_adminid, ADMIN_CALL_SETUP_ACK, "", 0, 0, 0);
2009 trace_header("SETUP ACKNOWLEDGE", DIRECTION_IN);
2011 if (e_dialing_queue[0] && portlist)
2013 /* send what we have not dialed yet, because we had no setup complete */
2014 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing pending digits: '%s'\n", ea_endpoint->ep_serial, e_dialing_queue);
2015 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
2016 SCPY(message->param.information.id, e_dialing_queue);
2017 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
2018 message_put(message);
2019 logmessage(message);
2020 e_dialing_queue[0] = '\0';
2022 /* check if pattern is available */
2023 if (!ea_endpoint->ep_portlist->next && portlist->early_b) /* one port_list relation and tones available */
2025 /* indicate patterns */
2026 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_PATTERN);
2027 message_put(message);
2029 /* connect audio, if not already */
2030 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2031 message->param.channel = CHANNEL_STATE_CONNECT;
2032 message_put(message);
2035 /* indicate no patterns */
2036 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_NOPATTERN);
2037 message_put(message);
2039 /* disconnect audio, if not already */
2040 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2041 message->param.channel = CHANNEL_STATE_HOLD;
2042 message_put(message);
2044 new_state(EPOINT_STATE_OUT_OVERLAP);
2045 /* if we are in a call */
2046 if (ea_endpoint->ep_call_id)
2048 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, message_type);
2049 memcpy(&message->param, param, sizeof(union parameter));
2050 message_put(message);
2054 /* port MESSAGE_PROCEEDING */
2055 void EndpointAppPBX::port_proceeding(struct port_list *portlist, int message_type, union parameter *param)
2057 struct message *message;
2059 /* signal to call tool */
2060 admin_call_response(e_adminid, ADMIN_CALL_PROCEEDING, "", 0, 0, 0);
2062 trace_header("PROCEEDING", DIRECTION_IN);
2064 e_state = EPOINT_STATE_OUT_PROCEEDING;
2065 /* check if pattern is availatle */
2066 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) /* one port_list relation and tones available */
2068 /* indicate patterns */
2069 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_PATTERN);
2070 message_put(message);
2072 /* connect audio, if not already */
2073 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2074 message->param.channel = CHANNEL_STATE_CONNECT;
2075 message_put(message);
2078 /* indicate no patterns */
2079 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_NOPATTERN);
2080 message_put(message);
2082 /* disconnect audio, if not already */
2083 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2084 message->param.channel = CHANNEL_STATE_HOLD;
2085 message_put(message);
2087 /* if we are in a call */
2088 if (ea_endpoint->ep_call_id)
2090 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, message_type);
2091 memcpy(&message->param, param, sizeof(union parameter));
2092 message_put(message);
2096 /* port MESSAGE_ALERTING */
2097 void EndpointAppPBX::port_alerting(struct port_list *portlist, int message_type, union parameter *param)
2099 struct message *message;
2101 /* signal to call tool */
2102 admin_call_response(e_adminid, ADMIN_CALL_ALERTING, "", 0, 0, 0);
2104 trace_header("ALERTING", DIRECTION_IN);
2106 new_state(EPOINT_STATE_OUT_ALERTING);
2107 /* check if pattern is available */
2108 if (!ea_endpoint->ep_portlist->next && (portlist->early_b || portlist->port_type==PORT_TYPE_VBOX_OUT)) /* one port_list relation and tones available */
2110 /* indicate patterns */
2111 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_PATTERN);
2112 message_put(message);
2114 /* connect audio, if not already */
2115 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2116 message->param.channel = CHANNEL_STATE_CONNECT;
2117 message_put(message);
2120 /* indicate no patterns */
2121 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_NOPATTERN);
2122 message_put(message);
2124 /* disconnect audio, if not already */
2125 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2126 message->param.channel = CHANNEL_STATE_HOLD;
2127 message_put(message);
2129 /* if we are in a call */
2130 if (ea_endpoint->ep_call_id)
2132 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, message_type);
2133 memcpy(&message->param, param, sizeof(union parameter));
2134 message_put(message);
2138 /* port MESSAGE_CONNECT */
2139 void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type, union parameter *param)
2141 struct message *message;
2143 unsigned long port_id = portlist->port_id;
2144 struct port_list *tportlist;
2147 /* signal to call tool */
2148 admin_call_response(e_adminid, ADMIN_CALL_CONNECT, numberrize_callerinfo(param->connectinfo.id,param->connectinfo.ntype), 0, 0, 0);
2150 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_connectinfo));
2151 trace_header("CONNECT", DIRECTION_IN);
2152 if (e_connectinfo.extension[0])
2153 add_trace("extension", NULL, "%s", e_connectinfo.extension);
2154 add_trace("connect id", "number", "%s", numberrize_callerinfo(e_connectinfo.id, e_connectinfo.ntype));
2155 if (e_connectinfo.present == INFO_PRESENT_RESTRICTED)
2156 add_trace("connect id", "present", "restricted");
2158 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (start)\n", ea_endpoint->ep_serial);
2159 while(ea_endpoint->ep_portlist->next) /* as long as we have at least two ports */
2161 tportlist = ea_endpoint->ep_portlist;
2162 if (tportlist->port_id == port_id) /* if the first portlist is the calling one, the second must be a different one */
2163 tportlist = tportlist->next;
2164 if (tportlist->port_id == port_id)
2166 PERROR("EPOINT(%d) software error: this should not happen since the portlist list must not have two links to the same port - exitting.\n");
2169 message = message_create(ea_endpoint->ep_serial, tportlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2170 message->param.disconnectinfo.cause = 26; /* non selected user clearing */
2171 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2172 message_put(message);
2173 logmessage(message);
2174 ea_endpoint->free_portlist(tportlist);
2176 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing all other ports (end)\n", ea_endpoint->ep_serial);
2180 /* screen incoming connected id */
2181 screen(0, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present);
2183 /* screen connected name */
2185 SCPY(e_connectinfo.name, e_ext.name);
2187 /* add internal id to colp */
2188 SCPY(e_connectinfo.extension, e_ext.number);
2190 /* we store the connected port number */
2191 SCPY(e_extension_interface, e_connectinfo.interfaces);
2193 /* for internal and am calls, we get the extension's id */
2194 if (portlist->port_type==PORT_TYPE_VBOX_OUT || e_ext.colp==COLP_HIDE)
2196 SCPY(e_connectinfo.id, e_ext.callerid);
2197 SCPY(e_connectinfo.extension, e_ext.number);
2198 e_connectinfo.itype = INFO_ITYPE_ISDN_EXTENSION;
2199 e_connectinfo.ntype = e_ext.callerid_type;
2200 e_connectinfo.present = e_ext.callerid_present;
2202 if (portlist->port_type==PORT_TYPE_VBOX_OUT)
2204 e_connectinfo.itype = INFO_ITYPE_VBOX;
2205 e_connectinfo.ntype = INFO_NTYPE_UNKNOWN;
2208 new_state(EPOINT_STATE_CONNECT);
2210 /* set volume of rx and tx */
2211 if (e_ext.txvol!=256 || e_ext.rxvol!=256)
2213 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2214 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2215 message->param.mISDNsignal.rxvol = e_ext.txvol;
2216 message->param.mISDNsignal.txvol = e_ext.rxvol;
2217 message_put(message);
2220 e_cfnr_call = e_cfnr_release = 0;
2221 if (e_ext.number[0])
2222 e_dtmf = 1; /* allow dtmf */
2223 // if (call_countrelations(ea_endpoint->ep_call_id) == 2)
2226 /* other calls with no caller id (or not available for the extension) and force colp */
2227 if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE)
2229 e_connectinfo.present = INFO_PRESENT_NOTAVAIL;
2230 if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) /* external extension answered */
2232 port = find_port_id(portlist->port_id);
2235 SCPY(e_connectinfo.id, nationalize_callerinfo(port->p_dialinginfo.id, &e_connectinfo.ntype));
2236 e_connectinfo.present = INFO_PRESENT_ALLOWED;
2240 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, message_type);
2241 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(struct connect_info));
2242 message_put(message);
2244 if (ea_endpoint->ep_call_id)
2246 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2247 message->param.channel = CHANNEL_STATE_CONNECT;
2248 message_put(message);
2249 } else if (!e_adminid)
2252 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have a callback, so we create a call with cbcaller: \"%s\".\n", ea_endpoint->ep_serial, e_cbcaller);
2253 SCPY(e_ext.number, e_cbcaller);
2254 new_state(EPOINT_STATE_IN_OVERLAP);
2255 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) callback from extension '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2257 /* get extension's info about terminal */
2258 if (!read_extension(&e_ext, e_ext.number))
2260 /* extension doesn't exist */
2261 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rejecting callback from not existing extension: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
2262 message_disconnect_port(portlist, CAUSE_REJECTED, LOCATION_PRIVATE_LOCAL, "");
2263 new_state(EPOINT_STATE_OUT_DISCONNECT);
2264 set_tone(portlist, "cause_80"); /* pbx cause: extension not authorized */
2268 /* put prefix in front of e_cbdialing */
2269 SPRINT(buffer, "%s%s", e_ext.prefix, e_cbdialing);
2270 SCPY(e_dialinginfo.id, buffer);
2271 e_dialinginfo.itype = INFO_ITYPE_ISDN;
2272 e_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
2274 /* use caller id (or if exist: id_next_call) for this call */
2275 e_callerinfo.screen = INFO_SCREEN_NETWORK;
2276 SCPY(e_callerinfo.extension, e_ext.number);
2277 if (e_ext.id_next_call_present >= 0)
2279 SCPY(e_callerinfo.id, e_ext.id_next_call);
2280 e_callerinfo.present = e_ext.id_next_call_present;
2281 e_callerinfo.ntype = e_ext.id_next_call_type;
2282 e_ext.id_next_call_present = -1;
2283 /* extension is written */
2284 write_extension(&e_ext, e_ext.number);
2287 SCPY(e_callerinfo.id, e_ext.callerid);
2288 e_callerinfo.present = e_ext.callerid_present;
2289 e_callerinfo.ntype = e_ext.callerid_type;
2292 e_connectedmode = 1; /* dtmf-hangup & disconnect prevention */
2295 /* check if caller id is NOT authenticated */
2296 if (!parse_callbackauth(e_ext.number, &e_callbackinfo))
2298 /* make call state to enter password */
2299 new_state(EPOINT_STATE_IN_OVERLAP);
2300 e_action = &action_password_write;
2301 e_match_timeout = 0;
2302 e_match_to_action = NULL;
2303 e_dialinginfo.id[0] = '\0';
2304 e_extdialing = strchr(e_dialinginfo.id, '\0');
2305 e_password_timeout = now+20;
2309 /* incoming call (callback) */
2310 e_ruleset = ruleset_main;
2312 e_rule = e_ruleset->rule_first;
2314 e_extdialing = e_dialinginfo.id;
2315 if (e_dialinginfo.id[0])
2317 set_tone(portlist, "dialing");
2321 set_tone(portlist, "dialpbx");
2324 } else /* testcall */
2326 set_tone(portlist, "hold");
2329 /* start recording if enabled, not when answering machine answers */
2330 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))
2332 /* check if we are a terminal */
2333 if (e_ext.number[0] == '\0')
2334 PERROR("Port(%d) cannot record because we are not a terminal\n", ea_endpoint->ep_serial);
2337 port = find_port_id(portlist->port_id);
2339 port->open_record(e_ext.record, 0, 0, e_ext.number, e_ext.anon_ignore, "", 0);
2344 /* port MESSAGE_DISCONNECT MESSAGE_RELEASE */
2345 void EndpointAppPBX::port_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
2347 struct message *message;
2349 unsigned long port_id = portlist->port_id;
2353 /* signal to call tool */
2354 admin_call_response(e_adminid, (message_type==MESSAGE_DISCONNECT)?ADMIN_CALL_DISCONNECT:ADMIN_CALL_RELEASE, "", param->disconnectinfo.cause, param->disconnectinfo.location, 0);
2356 trace_header((message_type==MESSAGE_DISCONNECT)?(char *)"DISCONNECT":(char *)"RELEASE", DIRECTION_IN);
2357 add_trace("cause", "value", "%d", param->disconnectinfo.cause);
2358 add_trace("cause", "location", "%d", param->disconnectinfo.location);
2361 //#warning does this work? only disconnect when incoming port hat not already disconnected yet?
2362 if (e_state==EPOINT_STATE_IN_DISCONNECT && message_type!=MESSAGE_RELEASE)// || e_state==EPOINT_STATE_OUT_DISCONNECT || e_state==EPOINT_STATE_IDLE)
2364 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are already disconnected.\n", ea_endpoint->ep_serial);
2369 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);
2370 if (param->disconnectinfo.cause == CAUSE_REJECTED) /* call rejected */
2372 e_multipoint_cause = CAUSE_REJECTED;
2373 e_multipoint_location = param->disconnectinfo.location;
2375 if (param->disconnectinfo.cause==CAUSE_NORMAL && e_multipoint_cause!=CAUSE_REJECTED) /* reject via hangup */
2377 e_multipoint_cause = CAUSE_NORMAL;
2378 e_multipoint_location = param->disconnectinfo.location;
2380 if (param->disconnectinfo.cause==CAUSE_BUSY && e_multipoint_cause!=CAUSE_REJECTED && e_multipoint_cause!=CAUSE_NORMAL) /* busy */
2382 e_multipoint_cause = CAUSE_BUSY;
2383 e_multipoint_location = param->disconnectinfo.location;
2385 if (param->disconnectinfo.cause==CAUSE_OUTOFORDER && e_multipoint_cause!=CAUSE_BUSY && e_multipoint_cause!=CAUSE_REJECTED && e_multipoint_cause!=CAUSE_NORMAL) /* no L1 */
2387 e_multipoint_cause = CAUSE_OUTOFORDER;
2388 e_multipoint_location = param->disconnectinfo.location;
2390 if (param->disconnectinfo.cause!=CAUSE_NOUSER && e_multipoint_cause!=CAUSE_OUTOFORDER && e_multipoint_cause!=CAUSE_BUSY && e_multipoint_cause!=CAUSE_REJECTED && e_multipoint_cause!=CAUSE_NORMAL) /* anything but not 18 */
2392 e_multipoint_cause = param->disconnectinfo.cause;
2393 e_multipoint_location = param->disconnectinfo.location;
2395 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) new multipoint cause %d location %d.\n", ea_endpoint->ep_serial, e_multipoint_cause, e_multipoint_location);
2397 /* check if we have more than one portlist relation and we just ignore the disconnect */
2398 if (ea_endpoint->ep_portlist) if (ea_endpoint->ep_portlist->next)
2400 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the disconnect was from a multipoint call. we just release that relation.\n", ea_endpoint->ep_serial);
2401 portlist = ea_endpoint->ep_portlist;
2404 if (portlist->port_id == port_id)
2406 portlist = portlist->next;
2410 PERROR("EPOINT(%d) software error: no portlist related to the calling port.\n", ea_endpoint->ep_serial);
2413 if (message_type != MESSAGE_RELEASE)
2415 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
2416 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
2417 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2418 message_put(message);
2419 logmessage(message);
2421 ea_endpoint->free_portlist(portlist);
2422 return; /* one relation removed */
2424 if (e_multipoint_cause)
2426 cause = e_multipoint_cause;
2427 location = e_multipoint_location;
2430 cause = param->disconnectinfo.cause;
2431 location = param->disconnectinfo.location;
2434 e_cfnr_call = e_cfnr_release = 0;
2436 /* process hangup */
2437 process_hangup(e_call_cause, e_call_location);
2438 e_multipoint_cause = 0;
2439 e_multipoint_location = LOCATION_PRIVATE_LOCAL;
2441 /* tone to disconnected end */
2442 SPRINT(buffer, "cause_%02x", cause);
2443 if (ea_endpoint->ep_portlist)
2444 set_tone(ea_endpoint->ep_portlist, buffer);
2446 new_state(EPOINT_STATE_IN_DISCONNECT);
2447 if (ea_endpoint->ep_call_id)
2449 int haspatterns = 0;
2450 /* check if pattern is available */
2451 if (ea_endpoint->ep_portlist)
2452 if (!ea_endpoint->ep_portlist->next && ea_endpoint->ep_portlist->early_b)
2453 if (callpbx_countrelations(ea_endpoint->ep_call_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
2454 && message_type != MESSAGE_RELEASE) // if we release, we are done
2458 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has patterns.\n", ea_endpoint->ep_serial);
2459 /* indicate patterns */
2460 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_PATTERN);
2461 message_put(message);
2462 /* connect audio, if not already */
2463 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2464 message->param.channel = CHANNEL_STATE_CONNECT;
2465 message_put(message);
2466 /* send disconnect */
2467 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, message_type);
2468 memcpy(&message->param, param, sizeof(union parameter));
2469 message_put(message);
2470 /* disable encryption if disconnected */
2471 //PERROR("REMOVE ME: state =%d, %d\n", e_crypt_state, e_crypt);
2473 cryptman_message(CI_DISCONNECT_IND, NULL, 0);
2477 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the port has no patterns.\n", ea_endpoint->ep_serial);
2480 release(RELEASE_ALL, location, cause, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, callcause, portcause */
2481 return; /* must exit here */
2484 /* port MESSAGE_TIMEOUT */
2485 void EndpointAppPBX::port_timeout(struct port_list *portlist, int message_type, union parameter *param)
2489 trace_header("TIMEOUT", DIRECTION_IN);
2490 message_type = MESSAGE_DISCONNECT;
2491 switch (param->state)
2493 case PORT_STATE_OUT_SETUP:
2494 case PORT_STATE_OUT_OVERLAP:
2495 add_trace("state", NULL, "outgoing setup/dialing");
2497 /* no user responding */
2498 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2499 return; /* must exit here */
2501 case PORT_STATE_IN_SETUP:
2502 case PORT_STATE_IN_OVERLAP:
2503 add_trace("state", NULL, "incoming setup/dialing");
2504 param->disconnectinfo.cause = CAUSE_INVALID; /* number incomplete */
2505 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2508 case PORT_STATE_OUT_PROCEEDING:
2509 add_trace("state", NULL, "outgoing proceeding");
2511 param->disconnectinfo.cause = CAUSE_NOUSER; /* no user responding */
2512 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2513 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOUSER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2514 return; /* must exit here */
2516 case PORT_STATE_IN_PROCEEDING:
2517 add_trace("state", NULL, "incoming proceeding");
2518 param->disconnectinfo.cause = CAUSE_NOUSER;
2519 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL; /* no user responding */
2522 case PORT_STATE_OUT_ALERTING:
2523 add_trace("state", NULL, "outgoing alerting");
2525 param->disconnectinfo.cause = CAUSE_NOANSWER; /* no answer */
2526 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2527 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NOANSWER, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2528 return; /* must exit here */
2530 case PORT_STATE_IN_ALERTING:
2531 add_trace("state", NULL, "incoming alerting");
2532 param->disconnectinfo.cause = CAUSE_NOANSWER;
2533 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2536 case PORT_STATE_IN_DISCONNECT:
2537 case PORT_STATE_OUT_DISCONNECT:
2538 add_trace("state", NULL, "disconnect");
2540 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) in this special case, we release due to disconnect timeout.\n", ea_endpoint->ep_serial);
2541 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL);
2542 return; /* must exit here */
2545 param->disconnectinfo.cause = 31; /* normal unspecified */
2546 param->disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
2549 /* release call, disconnect isdn */
2551 new_state(EPOINT_STATE_OUT_DISCONNECT);
2552 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
2553 SCPY(e_tone, cause);
2556 set_tone(portlist, cause);
2557 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
2558 portlist = portlist->next;
2560 release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, call, port */
2563 /* port MESSAGE_NOTIFY */
2564 void EndpointAppPBX::port_notify(struct port_list *portlist, int message_type, union parameter *param)
2566 struct message *message;
2570 /* signal to call tool */
2571 admin_call_response(e_adminid, ADMIN_CALL_NOTIFY, numberrize_callerinfo(param->notifyinfo.id,param->notifyinfo.ntype), 0, 0, param->notifyinfo.notify);
2572 if (param->notifyinfo.notify)
2574 e_rx_state = track_notify(e_rx_state, param->notifyinfo.notify);
2577 /* if we get notification from stack, local shows if we disabled/enabled audio stream */
2578 if (param->notifyinfo.local) switch(param->notifyinfo.notify)
2580 case INFO_NOTIFY_REMOTE_HOLD:
2581 case INFO_NOTIFY_USER_SUSPENDED:
2582 /* tell call about it */
2583 if (ea_endpoint->ep_call_id)
2585 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2586 message->param.channel = CHANNEL_STATE_HOLD;
2587 message_put(message);
2591 case INFO_NOTIFY_REMOTE_RETRIEVAL:
2592 case INFO_NOTIFY_USER_RESUMED:
2593 /* set volume of rx and tx */
2594 if (param->setup.callerinfo.itype == INFO_ITYPE_ISDN_EXTENSION)
2595 if (e_ext.txvol!=256 || e_ext.rxvol!=256)
2598 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
2599 message->param.mISDNsignal.message = mISDNSIGNAL_VOLUME;
2600 message->param.mISDNsignal.rxvol = e_ext.txvol;
2601 message->param.mISDNsignal.txvol = e_ext.rxvol;
2602 message_put(message);
2604 /* set current tone */
2606 set_tone(portlist, e_tone);
2607 /* tell call about it */
2608 if (ea_endpoint->ep_call_id)
2610 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
2611 message->param.channel = CHANNEL_STATE_CONNECT;
2612 message_put(message);
2617 /* get name of notify */
2618 switch(param->notifyinfo.notify)
2624 logtext = "USER_SUSPENDED";
2627 logtext = "BEARER_SERVICE_CHANGED";
2630 logtext = "USER_RESUMED";
2633 logtext = "CONFERENCE_ESTABLISHED";
2636 logtext = "CONFERENCE_DISCONNECTED";
2639 logtext = "OTHER_PARTY_ADDED";
2642 logtext = "ISOLATED";
2645 logtext = "REATTACHED";
2648 logtext = "OTHER_PARTY_ISOLATED";
2651 logtext = "OTHER_PARTY_REATTACHED";
2654 logtext = "OTHER_PARTY_SPLIT";
2657 logtext = "OTHER_PARTY_DISCONNECTED";
2660 logtext = "CONFERENCE_FLOATING";
2663 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
2666 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
2669 logtext = "CALL_IS_A_WAITING_CALL";
2672 logtext = "DIVERSION_ACTIVATED";
2675 logtext = "RESERVED_CT_1";
2678 logtext = "RESERVED_CT_2";
2681 logtext = "REVERSE_CHARGING";
2684 logtext = "REMOTE_HOLD";
2687 logtext = "REMOTE_RETRIEVAL";
2690 logtext = "CALL_IS_DIVERTING";
2693 SPRINT(buffer, "%d", param->notifyinfo.notify - 0x80);
2697 trace_header("NOTIFY", DIRECTION_IN);
2698 if (param->notifyinfo.notify)
2699 add_trace("indicator", NULL, "%s", logtext);
2700 if (param->notifyinfo.id)
2702 add_trace("redir'on", "number", "%s", numberrize_callerinfo(param->notifyinfo.id, param->notifyinfo.ntype));
2703 if (param->notifyinfo.present == INFO_PRESENT_RESTRICTED)
2704 add_trace("redir'on", "present", "restricted");
2706 if (param->notifyinfo.display[0])
2707 add_trace("display", NULL, "%s", param->notifyinfo.display);
2710 /* notify call if available */
2711 if (ea_endpoint->ep_call_id)
2713 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_NOTIFY);
2714 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
2715 message_put(message);
2720 /* port MESSAGE_FACILITY */
2721 void EndpointAppPBX::port_facility(struct port_list *portlist, int message_type, union parameter *param)
2723 struct message *message;
2725 trace_header("FACILITY", DIRECTION_IN);
2728 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_FACILITY);
2729 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
2730 message_put(message);
2733 /* port MESSAGE_SUSPEND */
2734 /* NOTE: before supending, the inactive-notification must be done in order to set call mixer */
2735 void EndpointAppPBX::port_suspend(struct port_list *portlist, int message_type, union parameter *param)
2737 trace_header("SUSPEND", DIRECTION_IN);
2739 /* epoint is now parked */
2740 ea_endpoint->ep_park = 1;
2741 memcpy(ea_endpoint->ep_park_callid, param->parkinfo.callid, sizeof(ea_endpoint->ep_park_callid));
2742 ea_endpoint->ep_park_len = (param->parkinfo.len>8)?8:param->parkinfo.len;
2744 /* remove port relation */
2745 ea_endpoint->free_portlist(portlist);
2748 /* port MESSAGE_RESUME */
2749 /* NOTE: before resume, the active-notification must be done in order to set call mixer */
2750 void EndpointAppPBX::port_resume(struct port_list *portlist, int message_type, union parameter *param)
2752 trace_header("RESUME", DIRECTION_IN);
2754 /* epoint is now resumed */
2755 ea_endpoint->ep_park = 0;
2760 /* port sends message to the endpoint
2762 void EndpointAppPBX::ea_message_port(unsigned long port_id, int message_type, union parameter *param)
2764 struct port_list *portlist;
2765 struct message *message;
2767 portlist = ea_endpoint->ep_portlist;
2770 if (port_id == portlist->port_id)
2772 portlist = portlist->next;
2776 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);
2780 // PDEBUG(DEBUG_EPOINT, "received message %d (terminal %s, caller id %s)\n", message, e_ext.number, e_callerinfo.id);
2781 switch(message_type)
2783 case MESSAGE_DATA: /* data from port */
2784 /* send back to source for recording */
2787 message = message_create(ea_endpoint->ep_serial, port_id, EPOINT_TO_PORT, message_type);
2788 memcpy(&message->param, param, sizeof(union parameter));
2789 message_put(message);
2792 /* check if there is a call */
2793 if (!ea_endpoint->ep_call_id)
2795 /* continue if only one portlist */
2796 if (ea_endpoint->ep_portlist->next != NULL)
2798 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, message_type);
2799 memcpy(&message->param, param, sizeof(union parameter));
2800 message_put(message);
2803 case MESSAGE_TONE_EOF: /* tone is end of file */
2804 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) current tone is now end of file.\n", ea_endpoint->ep_serial);
2807 if (e_action->index == ACTION_VBOX_PLAY)
2811 if (e_action->index == ACTION_EFI)
2818 case MESSAGE_TONE_COUNTER: /* counter info received */
2819 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);
2821 if (e_action->index == ACTION_VBOX_PLAY)
2823 e_vbox_counter = param->counter.current;
2824 if (param->counter.max >= 0)
2825 e_vbox_counter_max = param->counter.max;
2829 /* PORT sends SETUP message */
2831 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);
2832 if (e_state!=EPOINT_STATE_IDLE)
2834 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
2837 port_setup(portlist, message_type, param);
2840 /* PORT sends INFORMATION message */
2841 case MESSAGE_INFORMATION: /* additional digits received */
2842 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);
2843 port_information(portlist, message_type, param);
2846 /* PORT sends FACILITY message */
2847 case MESSAGE_FACILITY:
2848 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) incoming facility (terminal '%s', caller id '%s')\n", ea_endpoint->ep_serial, e_ext.number, e_callerinfo.id);
2849 port_facility(portlist, message_type, param);
2852 /* PORT sends DTMF message */
2853 case MESSAGE_DTMF: /* dtmf digits received */
2854 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);
2855 port_dtmf(portlist, message_type, param);
2858 /* PORT sends CRYPT message */
2859 case MESSAGE_CRYPT: /* crypt response received */
2860 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) crypt response=%d\n", ea_endpoint->ep_serial, param->crypt.type);
2861 port_crypt(portlist, message_type, param);
2864 /* PORT sends MORE message */
2865 case MESSAGE_OVERLAP:
2866 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);
2867 if (e_state != EPOINT_STATE_OUT_SETUP)
2869 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);
2872 port_overlap(portlist, message_type, param);
2875 /* PORT sends PROCEEDING message */
2876 case MESSAGE_PROCEEDING: /* port is proceeding */
2877 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);
2878 if (e_state!=EPOINT_STATE_OUT_SETUP
2879 && e_state!=EPOINT_STATE_OUT_OVERLAP)
2881 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);
2884 port_proceeding(portlist, message_type, param);
2887 /* PORT sends ALERTING message */
2888 case MESSAGE_ALERTING:
2889 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);
2890 if (e_state!=EPOINT_STATE_OUT_SETUP
2891 && e_state!=EPOINT_STATE_OUT_OVERLAP
2892 && e_state!=EPOINT_STATE_OUT_PROCEEDING)
2894 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);
2897 port_alerting(portlist, message_type, param);
2900 /* PORT sends CONNECT message */
2901 case MESSAGE_CONNECT:
2902 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);
2903 if (e_state!=EPOINT_STATE_OUT_SETUP
2904 && e_state!=EPOINT_STATE_OUT_OVERLAP
2905 && e_state!=EPOINT_STATE_OUT_PROCEEDING
2906 && e_state!=EPOINT_STATE_OUT_ALERTING)
2908 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
2911 port_connect(portlist, message_type, param);
2914 /* PORT sends DISCONNECT message */
2915 case MESSAGE_DISCONNECT: /* port is disconnected */
2916 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);
2917 port_disconnect_release(portlist, message_type, param);
2920 /* PORT sends a RELEASE message */
2921 case MESSAGE_RELEASE: /* port releases */
2922 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);
2923 /* portlist is release at port_disconnect_release, thanx Paul */
2924 port_disconnect_release(portlist, message_type, param);
2927 /* PORT sends a TIMEOUT message */
2928 case MESSAGE_TIMEOUT:
2929 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);
2930 port_timeout(portlist, message_type, param);
2931 break; /* release */
2933 /* PORT sends a NOTIFY message */
2934 case MESSAGE_NOTIFY:
2935 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);
2936 port_notify(portlist, message_type, param);
2939 /* PORT sends a SUSPEND message */
2940 case MESSAGE_SUSPEND:
2941 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);
2942 port_suspend(portlist, message_type, param);
2943 break; /* suspend */
2945 /* PORT sends a RESUME message */
2946 case MESSAGE_RESUME:
2947 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);
2948 port_resume(portlist, message_type, param);
2952 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);
2955 /* Note: this endpoint may be destroyed, so we MUST return */
2959 /* messages from port
2961 /* call MESSAGE_CRYPT */
2962 void EndpointAppPBX::call_crypt(struct port_list *portlist, int message_type, union parameter *param)
2964 switch(param->crypt.type)
2966 /* message from remote port to "crypt manager" */
2967 case CU_ACTK_REQ: /* activate key-exchange */
2968 case CU_ACTS_REQ: /* activate shared key */
2969 case CU_DACT_REQ: /* deactivate */
2970 case CU_INFO_REQ: /* request last info message */
2971 cryptman_message(param->crypt.type, param->crypt.data, param->crypt.len);
2974 /* message from "crypt manager" to user */
2975 case CU_ACTK_CONF: /* key-echange done */
2976 case CU_ACTS_CONF: /* shared key done */
2977 case CU_DACT_CONF: /* deactivated */
2978 case CU_DACT_IND: /* deactivated */
2979 case CU_ERROR_IND: /* receive error message */
2980 case CU_INFO_IND: /* receive info message */
2981 case CU_INFO_CONF: /* receive info message */
2982 encrypt_result(param->crypt.type, (char *)param->crypt.data);
2986 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);
2990 /* call MESSAGE_INFORMATION */
2991 void EndpointAppPBX::call_information(struct port_list *portlist, int message_type, union parameter *param)
2993 struct message *message;
2999 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3000 memcpy(&message->param.information, ¶m->information, sizeof(struct dialing_info));
3001 message_put(message);
3002 logmessage(message);
3003 portlist = portlist->next;
3007 /* call MESSAGE_FACILITY */
3008 void EndpointAppPBX::call_facility(struct port_list *portlist, int message_type, union parameter *param)
3010 struct message *message;
3012 if (!e_ext.facility)
3019 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_FACILITY);
3020 memcpy(&message->param.facilityinfo, ¶m->facilityinfo, sizeof(struct facility_info));
3021 message_put(message);
3022 logmessage(message);
3023 portlist = portlist->next;
3027 /* call MESSAGE_MORE */
3028 void EndpointAppPBX::call_overlap(struct port_list *portlist, int message_type, union parameter *param)
3030 struct message *message;
3032 new_state(EPOINT_STATE_IN_OVERLAP);
3035 if (e_call_pattern && e_ext.own_setup)
3037 /* disconnect audio */
3038 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3039 message->param.channel = CHANNEL_STATE_HOLD;
3040 message_put(message);
3042 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
3044 set_tone(portlist, "dialtone");
3047 if (e_ext.number[0])
3048 set_tone(portlist, "dialpbx");
3050 set_tone(portlist, "dialtone");
3053 /* call MESSAGE_PROCEEDING */
3054 void EndpointAppPBX::call_proceeding(struct port_list *portlist, int message_type, union parameter *param)
3056 struct message *message;
3058 new_state(EPOINT_STATE_IN_PROCEEDING);
3060 /* own proceeding tone */
3063 /* connect / disconnect audio */
3064 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3065 if (e_ext.own_proceeding)
3066 message->param.channel = CHANNEL_STATE_HOLD;
3068 message->param.channel = CHANNEL_STATE_CONNECT;
3069 message_put(message);
3071 // UCPY(e_call_tone, "proceeding");
3074 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3075 message_put(message);
3076 logmessage(message);
3078 set_tone(portlist, "proceeding");
3081 /* call MESSAGE_ALERTING */
3082 void EndpointAppPBX::call_alerting(struct port_list *portlist, int message_type, union parameter *param)
3084 struct message *message;
3086 new_state(EPOINT_STATE_IN_ALERTING);
3088 /* own alerting tone */
3091 /* connect / disconnect audio */
3092 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3093 if (e_ext.own_alerting)
3094 message->param.channel = CHANNEL_STATE_HOLD;
3096 message->param.channel = CHANNEL_STATE_CONNECT;
3097 message_put(message);
3101 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_ALERTING);
3102 message_put(message);
3103 logmessage(message);
3105 if (e_action) if (e_action->index == ACTION_OUTDIAL || e_action->index == ACTION_EXTERNAL)
3107 set_tone(portlist, "ringing");
3110 if (e_ext.number[0])
3111 set_tone(portlist, "ringpbx");
3113 set_tone(portlist, "ringing");
3116 /* call MESSAGE_CONNECT */
3117 void EndpointAppPBX::call_connect(struct port_list *portlist, int message_type, union parameter *param)
3119 struct message *message;
3121 new_state(EPOINT_STATE_CONNECT);
3122 // UCPY(e_call_tone, "");
3123 if (e_ext.number[0])
3124 e_dtmf = 1; /* allow dtmf */
3126 memcpy(&e_connectinfo, ¶m->connectinfo, sizeof(e_callerinfo));
3129 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3130 memcpy(&message->param, param, sizeof(union parameter));
3131 /* screen incoming caller id */
3132 screen(1, e_connectinfo.id, sizeof(e_connectinfo.id), &e_connectinfo.ntype, &e_connectinfo.present);
3133 memcpy(&message->param.connectinfo, &e_connectinfo, sizeof(e_connectinfo));
3135 /* screen clip if prefix is required */
3136 if (e_ext.number[0] && message->param.connectinfo.id[0] && e_ext.clip_prefix[0])
3138 SCPY(message->param.connectinfo.id, e_ext.clip_prefix);
3139 SCAT(message->param.connectinfo.id, numberrize_callerinfo(e_connectinfo.id,e_connectinfo.ntype));
3140 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3143 /* use internal caller id */
3144 if (e_ext.number[0] && e_connectinfo.extension[0] && (message->param.connectinfo.present!=INFO_PRESENT_RESTRICTED || e_ext.anon_ignore))
3146 SCPY(message->param.connectinfo.id, e_connectinfo.extension);
3147 message->param.connectinfo.ntype = INFO_NTYPE_UNKNOWN;
3150 /* handle restricted caller ids */
3151 apply_callerid_restriction(e_ext.anon_ignore, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
3152 /* display callerid if desired for extension */
3153 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));
3155 /* use conp, if enabld */
3157 message->param.connectinfo.name[0] = '\0';
3160 message_put(message);
3161 logmessage(message);
3163 set_tone(portlist, NULL);
3165 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3166 message->param.channel = CHANNEL_STATE_CONNECT;
3167 message_put(message);
3171 /* call MESSAGE_DISCONNECT MESSAGE_RELEASE */
3172 void EndpointAppPBX::call_disconnect_release(struct port_list *portlist, int message_type, union parameter *param)
3175 struct message *message;
3178 /* be sure that we are active */
3180 e_tx_state = NOTIFY_STATE_ACTIVE;
3182 /* we are powerdialing, if e_powerdialing is set and limit is not exceeded if given */
3183 if (e_powerdialing && ((e_powercount+1)<e_powerlimit || e_powerlimit<1))
3185 release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, call, port */
3187 /* set time for power dialing */
3188 e_powerdialing = now_d + e_powerdelay; /* set redial in the future */
3191 /* set redial tone */
3192 if (ea_endpoint->ep_portlist)
3196 set_tone(ea_endpoint->ep_portlist, "redial");
3197 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);
3198 /* send proceeding when powerdialing and still setup (avoid dialing timeout) */
3199 if (e_state==EPOINT_STATE_IN_OVERLAP)
3201 new_state(EPOINT_STATE_IN_PROCEEDING);
3204 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_PROCEEDING);
3205 message_put(message);
3206 logmessage(message);
3208 /* caused the error, that the first knock sound was not there */
3209 /* set_tone(portlist, "proceeding"); */
3211 /* send display of powerdialing */
3212 if (e_ext.display_dialing)
3216 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3218 SPRINT(message->param.notifyinfo.display, "Retry %d of %d", e_powercount, e_powerlimit);
3220 SPRINT(message->param.notifyinfo.display, "Retry %d", e_powercount);
3221 message_put(message);
3222 logmessage(message);
3223 portlist = portlist->next;
3232 if ((e_state!=EPOINT_STATE_CONNECT
3233 && e_state!=EPOINT_STATE_OUT_DISCONNECT
3234 && e_state!=EPOINT_STATE_IN_OVERLAP
3235 && e_state!=EPOINT_STATE_IN_PROCEEDING
3236 && e_state!=EPOINT_STATE_IN_ALERTING)
3237 || !ea_endpoint->ep_portlist) /* or no port */
3239 process_hangup(param->disconnectinfo.cause, param->disconnectinfo.location);
3240 release(RELEASE_ALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, param->disconnectinfo.cause); /* RELEASE_TYPE, call, port */
3241 return; /* must exit here */
3246 e_call_cause = param->disconnectinfo.cause;
3247 e_call_location = param->disconnectinfo.location;
3250 /* on release we need the audio again! */
3251 if (message_type == MESSAGE_RELEASE)
3254 ea_endpoint->ep_call_id = 0;
3256 /* disconnect and select tone */
3257 new_state(EPOINT_STATE_OUT_DISCONNECT);
3258 SPRINT(cause, "cause_%02x", param->disconnectinfo.cause);
3259 /* if own_cause, we must release the call */
3260 if (e_ext.own_cause /* own cause */
3261 || !e_call_pattern) /* no patterns */
3263 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_call_pattern);
3264 if (message_type != MESSAGE_RELEASE)
3265 release(RELEASE_CALL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, CAUSE_NORMAL); /* RELEASE_TYPE, call, port */
3267 } else /* else we enable audio */
3269 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3270 message->param.channel = CHANNEL_STATE_CONNECT;
3271 message_put(message);
3273 /* send disconnect message */
3274 SCPY(e_tone, cause);
3277 set_tone(portlist, cause);
3278 message_disconnect_port(portlist, param->disconnectinfo.cause, param->disconnectinfo.location, "");
3279 portlist = portlist->next;
3283 /* call MESSAGE_SETUP */
3284 void EndpointAppPBX::call_setup(struct port_list *portlist, int message_type, union parameter *param)
3286 struct message *message;
3288 /* if we already in setup state, we just update the dialing with new digits */
3289 if (e_state == EPOINT_STATE_OUT_SETUP
3290 || e_state == EPOINT_STATE_OUT_OVERLAP)
3292 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we are in setup state, so we do overlap dialing.\n", ea_endpoint->ep_serial);
3293 /* if digits changed, what we have already dialed */
3294 if (!!strncmp(e_dialinginfo.id,param->setup.dialinginfo.id,strlen(e_dialinginfo.id)))
3296 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);
3297 /* release all ports */
3298 while((portlist = ea_endpoint->ep_portlist))
3300 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_RELEASE);
3301 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal clearing */
3302 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3303 message_put(message);
3304 logmessage(message);
3305 ea_endpoint->free_portlist(portlist);
3308 /* disconnect audio */
3309 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3310 message->param.channel = CHANNEL_STATE_HOLD;
3311 message_put(message);
3313 /* get dialing info */
3314 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3315 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3316 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3317 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3318 new_state(EPOINT_STATE_OUT_OVERLAP);
3321 e_redial = now_d + 1; /* set redial one second in the future */
3324 /* if we have a pending redial, so we just adjust the dialing number */
3327 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);
3328 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3331 if (!ea_endpoint->ep_portlist)
3333 PERROR("ERROR: overlap dialing to a NULL port relation\n");
3335 if (ea_endpoint->ep_portlist->next)
3337 PERROR("ERROR: overlap dialing to a port_list port relation\n");
3339 if (e_state == EPOINT_STATE_OUT_SETUP)
3342 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);
3343 SCAT(e_dialing_queue, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3347 /* get what we have not dialed yet */
3348 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));
3349 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_INFORMATION);
3350 SCPY(message->param.information.id, param->setup.dialinginfo.id + strlen(e_dialinginfo.id));
3351 message->param.information.ntype = INFO_NTYPE_UNKNOWN;
3352 message_put(message);
3353 logmessage(message);
3355 /* always store what we have dialed or queued */
3356 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3360 if (e_state != EPOINT_STATE_IDLE)
3362 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in idle state.\n", ea_endpoint->ep_serial);
3365 /* if an internal extension is dialed, copy that number */
3366 if (param->setup.dialinginfo.itype==INFO_ITYPE_ISDN_EXTENSION || param->setup.dialinginfo.itype==INFO_ITYPE_VBOX)
3367 SCPY(e_ext.number, param->setup.dialinginfo.id);
3368 /* if an internal extension is dialed, get extension's info about caller */
3369 if (e_ext.number[0])
3371 if (!read_extension(&e_ext, e_ext.number))
3373 e_ext.number[0] = '\0';
3374 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) the called terminal='%s' is not found in directory tree!\n", ea_endpoint->ep_serial, e_ext.number);
3378 memcpy(&e_callerinfo, ¶m->setup.callerinfo, sizeof(e_callerinfo));
3379 memcpy(&e_dialinginfo, ¶m->setup.dialinginfo, sizeof(e_dialinginfo));
3380 memcpy(&e_redirinfo, ¶m->setup.redirinfo, sizeof(e_redirinfo));
3381 memcpy(&e_capainfo, ¶m->setup.capainfo, sizeof(e_capainfo));
3383 /* screen incoming caller id */
3384 screen(1, e_callerinfo.id, sizeof(e_callerinfo.id), &e_callerinfo.ntype, &e_callerinfo.present);
3386 /* process (voice over) data calls */
3387 if (e_ext.datacall && e_capainfo.bearer_capa!=INFO_BC_SPEECH && e_capainfo.bearer_capa!=INFO_BC_AUDIO)
3389 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) handling data call as audio call: '%s'\n", ea_endpoint->ep_serial, e_ext.number);
3390 memset(&e_capainfo, 0, sizeof(e_capainfo));
3391 e_capainfo.bearer_capa = INFO_BC_AUDIO;
3392 e_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
3393 e_capainfo.bearer_info1 = (options.law=='u')?INFO_INFO1_ULAW:INFO_INFO1_ALAW;
3396 new_state(EPOINT_STATE_OUT_SETUP);
3397 /* call special setup routine */
3401 /* call MESSAGE_mISDNSIGNAL */
3402 void EndpointAppPBX::call_mISDNsignal(struct port_list *portlist, int message_type, union parameter *param)
3404 struct message *message;
3408 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_mISDNSIGNAL);
3409 memcpy(&message->param, param, sizeof(union parameter));
3410 message_put(message);
3411 portlist = portlist->next;
3415 /* call MESSAGE_NOTIFY */
3416 void EndpointAppPBX::call_notify(struct port_list *portlist, int message_type, union parameter *param)
3418 struct message *message;
3421 if (param->notifyinfo.notify)
3423 new_state = track_notify(e_tx_state, param->notifyinfo.notify);
3424 // /* if notification was generated locally, we turn hold music on/off */
3425 // if (param->notifyinfo.local)
3426 // 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)
3431 if (new_state!=NOTIFY_STATE_HOLD && new_state!=NOTIFY_STATE_SUSPEND)
3435 set_tone(portlist, "");
3436 portlist = portlist->next;
3438 portlist = ea_endpoint->ep_portlist;
3443 if (new_state==NOTIFY_STATE_HOLD || new_state==NOTIFY_STATE_SUSPEND)
3447 set_tone(portlist, "hold");
3448 portlist = portlist->next;
3450 portlist = ea_endpoint->ep_portlist;
3455 /* save new state */
3456 e_tx_state = new_state;
3459 /* notify port(s) about it */
3462 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
3463 memcpy(&message->param.notifyinfo, ¶m->notifyinfo, sizeof(struct notify_info));
3464 /* handle restricted caller ids */
3465 apply_callerid_restriction(e_ext.anon_ignore, message->param.notifyinfo.id, &message->param.notifyinfo.ntype, &message->param.notifyinfo.present, 0, message->param.notifyinfo.extension, NULL);
3466 /* display callerid if desired for extension */
3467 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));
3468 message_put(message);
3469 logmessage(message);
3470 portlist = portlist->next;
3474 /* call sends messages to the endpoint
3476 void EndpointAppPBX::ea_message_call(unsigned long call_id, int message_type, union parameter *param)
3478 struct port_list *portlist;
3479 struct message *message;
3483 PERROR("EPOINT(%d) error: call == NULL.\n", ea_endpoint->ep_serial);
3487 portlist = ea_endpoint->ep_portlist;
3489 /* send MESSAGE_DATA to port */
3490 if (call_id == ea_endpoint->ep_call_id)
3492 if (message_type == MESSAGE_DATA)
3494 /* skip if no port relation */
3497 /* skip if more than one port relation */
3500 /* send audio data to port */
3501 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DATA);
3502 memcpy(&message->param, param, sizeof(union parameter));
3503 message_put(message);
3508 // PDEBUG(DEBUG_EPOINT, "EPOINT(%d) received message %d for active call (terminal %s, caller id %s state=%d)\n", ea_endpoint->ep_serial, message, e_ext.number, e_callerinfo.id, e_state);
3509 switch(message_type)
3511 /* CALL SENDS CRYPT message */
3513 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);
3514 call_crypt(portlist, message_type, param);
3517 /* CALL sends INFORMATION message */
3518 case MESSAGE_INFORMATION:
3519 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);
3520 call_information(portlist, message_type, param);
3523 /* CALL sends FACILITY message */
3524 case MESSAGE_FACILITY:
3525 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);
3526 call_facility(portlist, message_type, param);
3529 /* CALL sends OVERLAP message */
3530 case MESSAGE_OVERLAP:
3531 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);
3532 if (e_state!=EPOINT_STATE_IN_SETUP
3533 && e_state!=EPOINT_STATE_IN_OVERLAP)
3535 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3538 call_overlap(portlist, message_type, param);
3541 /* CALL sends PROCEEDING message */
3542 case MESSAGE_PROCEEDING:
3543 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);
3544 if(e_state!=EPOINT_STATE_IN_OVERLAP)
3546 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup state.\n", ea_endpoint->ep_serial);
3549 call_proceeding(portlist, message_type, param);
3552 /* CALL sends ALERTING message */
3553 case MESSAGE_ALERTING:
3554 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);
3555 if (e_state!=EPOINT_STATE_IN_OVERLAP
3556 && e_state!=EPOINT_STATE_IN_PROCEEDING)
3558 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup or proceeding state.\n", ea_endpoint->ep_serial);
3561 call_alerting(portlist, message_type, param);
3564 /* CALL sends CONNECT message */
3565 case MESSAGE_CONNECT:
3566 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);
3567 if (e_state!=EPOINT_STATE_IN_OVERLAP
3568 && e_state!=EPOINT_STATE_IN_PROCEEDING
3569 && e_state!=EPOINT_STATE_IN_ALERTING)
3571 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ignored because we are not in setup, proceeding or alerting state.\n", ea_endpoint->ep_serial);
3574 call_connect(portlist, message_type, param);
3577 /* CALL sends DISCONNECT/RELEASE message */
3578 case MESSAGE_DISCONNECT: /* call disconnect */
3579 case MESSAGE_RELEASE: /* call releases */
3580 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);
3581 call_disconnect_release(portlist, message_type, param);
3584 /* CALL sends SETUP message */
3586 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);
3587 call_setup(portlist, message_type, param);
3591 /* CALL sends special mISDNSIGNAL message */
3592 case MESSAGE_mISDNSIGNAL: /* isdn message to port */
3593 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);
3594 call_mISDNsignal(portlist, message_type, param);
3597 /* CALL has pattern available */
3598 case MESSAGE_PATTERN: /* indicating pattern available */
3599 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);
3600 if (!e_call_pattern)
3602 PDEBUG(DEBUG_EPOINT, "-> pattern becomes available\n");
3607 set_tone(portlist, NULL);
3608 portlist = portlist->next;
3610 /* connect our audio tx and rx (blueboxing should be possibe before connect :)*/
3611 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3612 message->param.channel = CHANNEL_STATE_CONNECT;
3613 message_put(message);
3614 // /* tell remote epoint to connect audio also, because we like to hear the patterns */
3615 // message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_REMOTE_AUDIO);
3616 // message->param.channel = CHANNEL_STATE_CONNECT;
3617 // message_put(message);
3618 // patterns are available, remote already connected audio
3622 /* CALL has no pattern available */
3623 case MESSAGE_NOPATTERN: /* indicating no pattern available */
3624 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);
3627 PDEBUG(DEBUG_EPOINT, "-> pattern becomes unavailable\n");
3629 /* disconnect our audio tx and rx */
3630 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3631 message->param.channel = CHANNEL_STATE_HOLD;
3632 message_put(message);
3637 /* CALL (dunno at the moment) */
3638 case MESSAGE_REMOTE_AUDIO:
3639 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);
3640 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3641 message->param.channel = param->channel;
3642 message_put(message);
3646 /* CALL sends a notify message */
3647 case MESSAGE_NOTIFY:
3648 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);
3649 call_notify(portlist, message_type, param);
3653 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);
3658 /* pick_call will connect the first incoming call found. the endpoint
3659 * will receivce a MESSAGE_CONNECT.
3661 int match_list(char *list, char *item)
3663 char *end, *next = NULL;
3665 /* no list make matching */
3671 /* eliminate white spaces */
3672 while (*list <= ' ')
3679 /* if end of list is reached, we return */
3680 if (list[0] == '\0')
3682 /* if we have more than one entry (left) */
3683 if ((end = strchr(list, ',')))
3686 next = end = strchr(list, '\0');
3687 while (*(end-1) <= ' ')
3689 /* if string part matches item */
3690 if (!strncmp(list, item, end-list))
3696 void EndpointAppPBX::pick_call(char *extensions)
3698 struct message *message;
3699 struct port_list *portlist;
3701 class EndpointAppPBX *eapp, *found;
3703 class CallPBX *callpbx;
3704 struct call_relation *relation;
3707 /* find an endpoint that is ringing internally or vbox with higher priority */
3710 eapp = apppbx_first;
3713 if (eapp!=this && ea_endpoint->ep_portlist)
3715 portlist = eapp->ea_endpoint->ep_portlist;
3718 if ((port = find_port_id(portlist->port_id)))
3720 if (port->p_type == PORT_TYPE_VBOX_OUT)
3722 if (match_list(extensions, eapp->e_ext.number))
3729 if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT)
3730 && port->p_state==PORT_STATE_OUT_ALERTING)
3731 if (match_list(extensions, eapp->e_ext.number))
3736 portlist = portlist->next;
3744 /* if no endpoint found */
3747 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);
3749 set_tone(ea_endpoint->ep_portlist, "cause_10");
3750 message_disconnect_port(ea_endpoint->ep_portlist, CAUSE_NORMAL, LOCATION_PRIVATE_LOCAL, "");
3751 new_state(EPOINT_STATE_OUT_DISCONNECT);
3756 if (ea_endpoint->ep_call_id)
3758 PERROR("EPOINT(%d) we already have a call. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3761 if (!eapp->ea_endpoint->ep_call_id)
3763 PERROR("EPOINT(%d) ringing endpoint has no call.\n", ea_endpoint->ep_serial);
3766 call = find_call_id(eapp->ea_endpoint->ep_call_id);
3769 PERROR("EPOINT(%d) ringing endpoint's call not found.\n", ea_endpoint->ep_serial);
3772 if (callpbx->c_type != CALL_TYPE_PBX)
3774 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) ringing endpoint's call is not a PBX call, so we must reject.\n", ea_endpoint->ep_serial);
3777 callpbx = (class CallPBX *)call;
3778 relation = callpbx->c_relation;
3781 PERROR("EPOINT(%d) ringing endpoint's call has no relation. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3784 while (relation->epoint_id != eapp->ea_endpoint->ep_serial)
3786 relation = relation->next;
3789 PERROR("EPOINT(%d) ringing endpoint's call has no relation to that call. SOFTWARE ERROR.\n", ea_endpoint->ep_serial);
3794 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) found ringing endpoint: %d.\n", ea_endpoint->ep_serial, eapp->ea_endpoint->ep_serial);
3796 if (options.deb & DEBUG_EPOINT)
3798 class Call *debug_c = call_first;
3799 class Endpoint *debug_e = epoint_first;
3800 class Port *debug_p = port_first;
3802 callpbx_debug(callpbx, "EndpointAppPBX::pick_call(before)");
3804 PDEBUG(DEBUG_EPOINT, "showing all calls:\n");
3807 PDEBUG(DEBUG_EPOINT, "call=%ld\n", debug_c->c_serial);
3808 debug_c = debug_c->next;
3810 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3813 PDEBUG(DEBUG_EPOINT, "ep=%ld, call=%ld\n", debug_e->ep_serial, debug_e->ep_call_id);
3814 debug_e = debug_e->next;
3816 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3819 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld (active)\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3820 debug_p = debug_p->next;
3825 ea_endpoint->ep_call_id = eapp->ea_endpoint->ep_call_id; /* we get the call */
3826 relation->epoint_id = ea_endpoint->ep_serial; /* the call gets us */
3827 eapp->ea_endpoint->ep_call_id = 0; /* the ringing endpoint will get disconnected */
3829 /* connnecting our endpoint */
3830 new_state(EPOINT_STATE_CONNECT);
3832 set_tone(ea_endpoint->ep_portlist, NULL);
3834 /* now we send a release to the ringing endpoint */
3835 message = message_create(ea_endpoint->ep_call_id, eapp->ea_endpoint->ep_serial, CALL_TO_EPOINT, MESSAGE_RELEASE);
3836 message->param.disconnectinfo.cause = 26; /* non selected user clearing */
3837 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
3838 message_put(message);
3840 /* we send a connect to the call with our caller id */
3841 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CONNECT);
3842 SCPY(message->param.connectinfo.id, e_callerinfo.id);
3843 message->param.connectinfo.present = e_callerinfo.present;
3844 message->param.connectinfo.screen = e_callerinfo.screen;
3845 message->param.connectinfo.itype = e_callerinfo.itype;
3846 message->param.connectinfo.ntype = e_callerinfo.ntype;
3847 message_put(message);
3849 /* we send a connect to our port with the remote callerid */
3850 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
3851 SCPY(message->param.connectinfo.id, eapp->e_callerinfo.id);
3852 message->param.connectinfo.present = eapp->e_callerinfo.present;
3853 message->param.connectinfo.screen = eapp->e_callerinfo.screen;
3854 message->param.connectinfo.itype = eapp->e_callerinfo.itype;
3855 message->param.connectinfo.ntype = eapp->e_callerinfo.ntype;
3856 /* handle restricted caller ids */
3857 apply_callerid_restriction(e_ext.anon_ignore, message->param.connectinfo.id, &message->param.connectinfo.ntype, &message->param.connectinfo.present, &message->param.connectinfo.screen, message->param.connectinfo.extension, message->param.connectinfo.name);
3858 /* display callerid if desired for extension */
3859 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));
3860 message_put(message);
3862 /* we send a connect to the audio path (not for vbox) */
3863 message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_call_id, EPOINT_TO_CALL, MESSAGE_CHANNEL);
3864 message->param.channel = CHANNEL_STATE_CONNECT;
3865 message_put(message);
3867 /* beeing paranoid, we make call update */
3868 callpbx->c_updatebridge = 1;
3870 if (options.deb & DEBUG_EPOINT)
3872 class Call *debug_c = call_first;
3873 class Endpoint *debug_e = epoint_first;
3874 class Port *debug_p = port_first;
3876 callpbx_debug(callpbx, "EndpointAppPBX::pick_call(after)");
3878 PDEBUG(DEBUG_EPOINT, "showing all calls:\n");
3881 PDEBUG(DEBUG_EPOINT, "call=%ld\n", debug_c->c_serial);
3882 debug_c = debug_c->next;
3884 PDEBUG(DEBUG_EPOINT, "showing all endpoints:\n");
3887 PDEBUG(DEBUG_EPOINT, "ep=%ld, call=%ld\n", debug_e->ep_serial, debug_e->ep_call_id);
3888 debug_e = debug_e->next;
3890 PDEBUG(DEBUG_EPOINT, "showing all ports:\n");
3893 PDEBUG(DEBUG_EPOINT, "port=%ld, ep=%ld\n", debug_p->p_serial, ACTIVE_EPOINT(debug_p->p_epointlist));
3894 debug_p = debug_p->next;
3900 /* join calls (look for a call that is on hold (same isdn interface/terminal))
3902 void EndpointAppPBX::join_call(void)
3904 struct message *message;
3905 struct call_relation *our_relation, *other_relation;
3906 struct call_relation **our_relation_pointer, **other_relation_pointer;
3907 class Call *our_call, *other_call;
3908 class CallPBX *our_callpbx, *other_callpbx;
3909 class EndpointAppPBX *other_eapp; class Endpoint *temp_epoint;
3910 class Port *our_port, *other_port;
3911 class Pdss1 *our_pdss1, *other_pdss1;
3913 /* are we a candidate to join a call */
3914 our_call = find_call_id(ea_endpoint->ep_call_id);
3917 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our call doesn't exist anymore.\n", ea_endpoint->ep_serial);
3920 if (our_call->c_type != CALL_TYPE_PBX)
3922 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: call is not a pbx call.\n", ea_endpoint->ep_serial);
3925 our_callpbx = (class CallPBX *)our_call;
3926 if (!ea_endpoint->ep_portlist)
3928 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we have no port.\n", ea_endpoint->ep_serial);
3931 if (!e_ext.number[0])
3933 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we are not internal extension.\n", ea_endpoint->ep_serial);
3936 our_port = find_port_id(ea_endpoint->ep_portlist->port_id);
3939 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port doesn't exist anymore.\n", ea_endpoint->ep_serial);
3942 if ((our_port->p_type&PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
3944 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: our port is not isdn.\n", ea_endpoint->ep_serial);
3947 our_pdss1 = (class Pdss1 *)our_port;
3949 /* find an endpoint that is on hold and has the same mISDNport that we are on */
3950 other_eapp = apppbx_first;
3953 if (other_eapp == this)
3955 other_eapp = other_eapp->next;
3958 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint candiate: (ep%d) terminal='%s' port=%s call=%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_call_id);
3959 if (other_eapp->e_ext.number[0] /* has terminal */
3960 && other_eapp->ea_endpoint->ep_portlist /* has port */
3961 && other_eapp->ea_endpoint->ep_call_id) /* has call */
3963 other_port = find_port_id(other_eapp->ea_endpoint->ep_portlist->port_id);
3964 if (other_port) /* port still exists */
3966 if (other_port->p_type==PORT_TYPE_DSS1_NT_OUT
3967 || other_port->p_type==PORT_TYPE_DSS1_NT_IN) /* port is isdn nt-mode */
3969 other_pdss1 = (class Pdss1 *)other_port;
3970 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);
3971 if (other_pdss1->p_m_hold /* port is on hold */
3972 && other_pdss1->p_m_mISDNport == our_pdss1->p_m_mISDNport /* same isdn interface */
3973 && other_pdss1->p_m_d_ces == our_pdss1->p_m_d_ces) /* same tei+sapi */
3977 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port is of other type!\n", ea_endpoint->ep_serial);
3981 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) comparing other endpoint's port doesn't exist enymore.\n", ea_endpoint->ep_serial);
3984 other_eapp = other_eapp->next;
3988 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: no other endpoint on same isdn interface with port on hold.\n", ea_endpoint->ep_serial);
3991 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) port on hold found.\n", ea_endpoint->ep_serial);
3993 /* if we have the same call */
3994 if (other_eapp->ea_endpoint->ep_call_id == ea_endpoint->ep_call_id)
3996 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: we an the other have the same call.\n", ea_endpoint->ep_serial);
3999 other_call = find_call_id(other_eapp->ea_endpoint->ep_call_id);
4002 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other call doesn't exist anymore.\n", ea_endpoint->ep_serial);
4005 if (other_call->c_type != CALL_TYPE_PBX)
4007 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: other call is not a pbx call.\n", ea_endpoint->ep_serial);
4010 other_callpbx = (class CallPBX *)other_call;
4011 if (our_callpbx->c_partyline && other_callpbx->c_partyline)
4013 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) cannot join: both calls are partylines.\n", ea_endpoint->ep_serial);
4017 /* remove relation to endpoint for call on hold */
4018 other_relation = other_callpbx->c_relation;
4019 other_relation_pointer = &other_callpbx->c_relation;
4020 while(other_relation)
4022 if (other_relation->epoint_id == other_eapp->ea_endpoint->ep_serial)
4024 /* detach other endpoint on hold */
4025 *other_relation_pointer = other_relation->next;
4026 memset(other_relation, 0, sizeof(struct call_relation));
4027 free(other_relation);
4029 other_relation = *other_relation_pointer;
4030 other_eapp->ea_endpoint->ep_call_id = NULL;
4034 /* change call/hold pointer of endpoint to the new call */
4035 temp_epoint = find_epoint_id(other_relation->epoint_id);
4038 if (temp_epoint->ep_call_id == other_call->c_serial)
4039 temp_epoint->ep_call_id = our_call->c_serial;
4042 other_relation_pointer = &other_relation->next;
4043 other_relation = other_relation->next;
4045 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) endpoint on hold removed, other enpoints on call relinked (to our call).\n", ea_endpoint->ep_serial);
4047 /* join call relations */
4048 our_relation = our_callpbx->c_relation;
4049 our_relation_pointer = &our_callpbx->c_relation;
4052 our_relation_pointer = &our_relation->next;
4053 our_relation = our_relation->next;
4055 *our_relation_pointer = other_callpbx->c_relation;
4056 other_callpbx->c_relation = NULL;
4057 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) relations joined.\n", ea_endpoint->ep_serial);
4059 /* release endpoint on hold */
4060 message = message_create(other_callpbx->c_serial, other_eapp->ea_endpoint->ep_serial, CALL_TO_EPOINT, MESSAGE_RELEASE);
4061 message->param.disconnectinfo.cause = CAUSE_NORMAL; /* normal */
4062 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
4063 message_put(message);
4065 /* if we are not a partyline, we get partyline state from other call */
4066 our_callpbx->c_partyline += other_callpbx->c_partyline;
4068 /* remove empty call */
4070 PDEBUG(DEBUG_EPOINT, "EPOINT(%d)d-call completely removed!\n");
4072 /* mixer must update */
4073 our_callpbx->c_updatebridge = 1; /* update mixer flag */
4075 /* we send a retrieve to that endpoint */
4076 // mixer will update the hold-state of the call and send it to the endpoints is changes
4080 /* check if we have an external call
4081 * this is used to check for encryption ability
4083 int EndpointAppPBX::check_external(char **errstr, class Port **port)
4085 struct call_relation *relation;
4087 class CallPBX *callpbx;
4088 class Endpoint *epoint;
4090 /* some paranoia check */
4091 if (!ea_endpoint->ep_portlist)
4093 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we have no port.\n", ea_endpoint->ep_serial);
4094 *errstr = "No Call";
4097 if (!e_ext.number[0])
4099 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) error: we are not internal extension.\n", ea_endpoint->ep_serial);
4100 *errstr = "No Call";
4104 /* check if we have a call with 2 parties */
4105 call = find_call_id(ea_endpoint->ep_call_id);
4108 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) we have currently no call.\n", ea_endpoint->ep_serial);
4109 *errstr = "No Call";
4112 if (call->c_type != CALL_TYPE_PBX)
4114 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call is nto a pbx call.\n", ea_endpoint->ep_serial);
4115 *errstr = "No PBX Call";
4118 callpbx = (class CallPBX *)call;
4119 relation = callpbx->c_relation;
4122 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call has no relation.\n", ea_endpoint->ep_serial);
4123 *errstr = "No Call";
4126 if (!relation->next)
4128 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call has no 2nd relation.\n", ea_endpoint->ep_serial);
4129 *errstr = "No Call";
4132 if (relation->next->next)
4134 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call has more than two relations.\n", ea_endpoint->ep_serial);
4135 *errstr = "Err: Conference";
4138 if (relation->epoint_id == ea_endpoint->ep_serial)
4140 relation = relation->next;
4141 if (relation->epoint_id == ea_endpoint->ep_serial)
4143 PERROR("EPOINT(%d) SOFTWARE ERROR: both call relations are related to our endpoint.\n", ea_endpoint->ep_serial);
4144 *errstr = "Software Error";
4149 /* check remote port for external call */
4150 epoint = find_epoint_id(relation->epoint_id);
4153 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) call has no 2nd endpoint.\n", ea_endpoint->ep_serial);
4154 *errstr = "No Call";
4157 if (!epoint->ep_portlist)
4159 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not port.\n", ea_endpoint->ep_serial);
4160 *errstr = "No Call";
4163 *port = find_port_id(epoint->ep_portlist->port_id);
4166 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has an none existing port.\n", ea_endpoint->ep_serial);
4167 *errstr = "No Call";
4170 if (((*port)->p_type&PORT_CLASS_mISDN_MASK)!=PORT_CLASS_mISDN_DSS1) /* port is not external isdn */
4172 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint has not an external port.\n", ea_endpoint->ep_serial);
4173 *errstr = "No Ext Call";
4176 if ((*port)->p_state != PORT_STATE_CONNECT)
4178 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) 2nd endpoint's port is not in connected state.\n", ea_endpoint->ep_serial);
4179 *errstr = "No Ext Connect";
4185 void EndpointAppPBX::logmessage(struct message *message)
4187 char *logtext = "unknown";
4190 if (message->flow != EPOINT_TO_PORT)
4192 PERROR("EPOINT(%d) message not of correct flow type-\n", ea_endpoint->ep_serial);
4196 switch(message->type)
4199 trace_header("SETUP", DIRECTION_OUT);
4200 if (message->param.setup.callerinfo.extension[0])
4201 add_trace("extension", NULL, "%s", message->param.setup.callerinfo.extension);
4202 add_trace("caller id", "number", "%s", numberrize_callerinfo(message->param.setup.callerinfo.id, message->param.setup.callerinfo.ntype));
4203 if (message->param.setup.callerinfo.present == INFO_PRESENT_RESTRICTED)
4204 add_trace("caller id", "present", "restricted");
4205 if (message->param.setup.redirinfo.id[0])
4207 add_trace("redir'ing", "number", "%s", numberrize_callerinfo(message->param.setup.redirinfo.id, message->param.setup.redirinfo.ntype));
4208 if (message->param.setup.redirinfo.present == INFO_PRESENT_RESTRICTED)
4209 add_trace("redir'ing", "present", "restricted");
4211 if (message->param.setup.dialinginfo.id[0])
4212 add_trace("dialing", NULL, "%s", message->param.setup.dialinginfo.id);
4216 case MESSAGE_OVERLAP:
4217 trace_header("SETUP ACKNOWLEDGE", DIRECTION_OUT);
4221 case MESSAGE_PROCEEDING:
4222 trace_header("PROCEEDING", DIRECTION_OUT);
4226 case MESSAGE_ALERTING:
4227 trace_header("ALERTING", DIRECTION_OUT);
4231 case MESSAGE_CONNECT:
4232 trace_header("CONNECT", DIRECTION_OUT);
4233 if (message->param.connectinfo.extension[0])
4234 add_trace("extension", NULL, "%s", message->param.connectinfo.extension);
4235 add_trace("connect id", "number", "%s", numberrize_callerinfo(message->param.connectinfo.id, message->param.connectinfo.ntype));
4236 if (message->param.connectinfo.present == INFO_PRESENT_RESTRICTED)
4237 add_trace("connect id", "present", "restricted");
4241 case MESSAGE_DISCONNECT:
4242 trace_header("DISCONNECT", DIRECTION_OUT);
4243 add_trace("cause", "value", "%d", message->param.disconnectinfo.cause);
4244 add_trace("cause", "location", "%d", message->param.disconnectinfo.location);
4248 case MESSAGE_RELEASE:
4249 trace_header("RELEASE", DIRECTION_OUT);
4250 add_trace("cause", "value", "%d", message->param.disconnectinfo.cause);
4251 add_trace("cause", "location", "%d", message->param.disconnectinfo.location);
4255 case MESSAGE_NOTIFY:
4256 switch(message->param.notifyinfo.notify)
4262 logtext = "USER_SUSPENDED";
4265 logtext = "BEARER_SERVICE_CHANGED";
4268 logtext = "USER_RESUMED";
4271 logtext = "CONFERENCE_ESTABLISHED";
4274 logtext = "CONFERENCE_DISCONNECTED";
4277 logtext = "OTHER_PARTY_ADDED";
4280 logtext = "ISOLATED";
4283 logtext = "REATTACHED";
4286 logtext = "OTHER_PARTY_ISOLATED";
4289 logtext = "OTHER_PARTY_REATTACHED";
4292 logtext = "OTHER_PARTY_SPLIT";
4295 logtext = "OTHER_PARTY_DISCONNECTED";
4298 logtext = "CONFERENCE_FLOATING";
4301 logtext = "CONFERENCE_DISCONNECTED_PREEMTED";
4304 logtext = "CONFERENCE_FLOATING_SERVED_USER_PREEMTED";
4307 logtext = "CALL_IS_A_WAITING_CALL";
4310 logtext = "DIVERSION_ACTIVATED";
4313 logtext = "RESERVED_CT_1";
4316 logtext = "RESERVED_CT_2";
4319 logtext = "REVERSE_CHARGING";
4322 logtext = "REMOTE_HOLD";
4325 logtext = "REMOTE_RETRIEVAL";
4328 logtext = "CALL_IS_DIVERTING";
4331 SPRINT(buffer, "%d", message->param.notifyinfo.notify - 0x80);
4335 trace_header("NOTIFY", DIRECTION_OUT);
4336 if (message->param.notifyinfo.notify)
4337 add_trace("indicator", NULL, "%s", logtext);
4338 if (message->param.notifyinfo.id[0])
4340 add_trace("redir'on", "number", "%s", numberrize_callerinfo(message->param.notifyinfo.id, message->param.notifyinfo.ntype));
4341 if (message->param.notifyinfo.present == INFO_PRESENT_RESTRICTED)
4342 add_trace("redir'on", "present", "restricted");
4344 if (message->param.notifyinfo.display[0])
4345 add_trace("display", NULL, "%s", message->param.notifyinfo.display);
4349 case MESSAGE_INFORMATION:
4350 trace_header("INFORMATION", DIRECTION_OUT);
4351 add_trace("dialing", NULL, "%s", message->param.information.id);
4355 case MESSAGE_FACILITY:
4356 trace_header("FACILITY", DIRECTION_OUT);
4361 trace_header("TONE", DIRECTION_OUT);
4362 if (message->param.tone.name[0])
4364 add_trace("directory", NULL, "%s", message->param.tone.dir[0]?message->param.tone.dir:"default");
4365 add_trace("name", NULL, "%s", message->param.tone.name);
4367 add_trace("off", NULL, NULL);
4372 PERROR("EPOINT(%d) message not of correct type (%d)\n", ea_endpoint->ep_serial, message->type);
4376 void EndpointAppPBX::message_disconnect_port(struct port_list *portlist, int cause, int location, char *display)
4378 struct message *message;
4382 if (!portlist->port_id)
4385 if (!e_connectedmode)
4387 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_DISCONNECT);
4388 message->param.disconnectinfo.cause = cause;
4389 message->param.disconnectinfo.location = location;
4391 SCPY(message->param.disconnectinfo.display, display);
4393 SCPY(message->param.disconnectinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4396 message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
4398 SCPY(message->param.notifyinfo.display, display);
4400 SCPY(message->param.notifyinfo.display, get_isdn_cause(cause, location, e_ext.display_cause));
4402 message_put(message);
4403 logmessage(message);